面试题【HTTP协议详细,Django请求生命周期详细,中间件应用,跨域,ORM操作以及其他】
写博客前,导师给发了一道懵逼的面试题,虽然开发用不到,但是还是知道的好!
num=55.3 i=int(num) ta=float((num-i)*100) tb=int(ta) print(ta,tb) #29.99999999915 29
这是一个C++的面试题,首先num是55.3,i=int(num),那么i=53,接着ta=55.3-55=0.3,然后乘以100,就是30,tb=30.
感觉按着思路一步步没毛病,可是计算机却不这么想!
运行完发现是29.99999999999716,和29为什么和想象中不一样呢?那么这个问题是因为数字在计算机中是二进制存储的,
小数的存储没有正好二进制对应,所以只是无限接近。
0.3就是0.3000000000000000004,无限接近却不是3。
同样的这个也是这个样子,所以下面的结果也就容易想通了!
开始笔记
1.HTTP协议
----我理解的Http协议就是传输的格式。
----请求链接,请求完就断开(无状态,短连接)
往下会继续问头里和体里有什么?
2.关于web框架
我原来的学习django框架,从socket服务端开始学起。(一定要说)自己创造了一个docket服务器来充当:网站,浏览器当socket客户端更清楚的明白到底http协议是什么? -请求头 \r\n\r\n 请求体 -响应头 \r\n\r\n 响应体
2.常见的请求头:
refer ,host,content-type user-agent[列出来背]上一篇有具体的
3.常见的请求体(有可能会问到常见的请求体):
首先要明确的是
---GET没有请求体
---POST的请求体:
不同的方式下:
Form表单提交:
POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\nusername=alex&passwd=123&xxx=xxx...
Ajax请求: POST /index http1.1\r\nhost:www.luffycity.com...\r\n\r\n{"username":"alex","passwd":"123"}
补充:
django获取请求体:
如果前面的ajax发送的get请求: $.ajax({ url: "/check_username_exist/", type: "get", data: {"username": username},
后端可以通过request.GET.get拿到 username = request.GET.get("username")
但是如果是POST的ajax请求,不能通过request.POST.get拿到,django的request.POST不支持解析json格式,只支持urlencode.但是rest-framework支持所有格式。
-request.body(通过body可以拿到原生数据,需要自己解析)
-request.POST
4.Django请求生命周期:
首先要知道WSGI是什么?
-wsgi:就是socket服务端,用于接受用户请求并将请求进行初次封装,然后将请求交给web框架(django,flask)
(1)请求进入
请求进来,wsgi(socket服务端)做一次初步的封装(request)
(2)再到django进行二次封装。(request对象)
源码中WSGIHandler()里面的__call__方法
request=self.request_class(environ)
解析:environ就是第一次封装
request=self.request_class(environ)第二次封装
[request_class=WSGIRequest]
(3)经过中间件,帮助我们队请求进行校验火灾请求对象中添加其他数据,
如csrf_token,request.session
(4)进入路由匹配
找到视图函数之后,执行视图函数进行业务逻辑的处理
-->可能会涉及到数据库的操作(ORM)
-->可能会涉及到模板的渲染(render)
(5)往回返response的时候通过中间件的process_response方法进行处理.
(6)然后通过wsgi返回给浏览器(用户)。[其实就是socket的sendall]
讲生命周期,应该把每一步是干什么的说清楚最好!!!
5.中间件
---5个方法
---应用场景:
----登录认证(由登录验证的装饰器而来,如果视图函数太多,总不能一个个的去加装饰器吧)
----权限(设置访问白名单)***着重关注(公司对权限都很感兴趣)
权限基本实现的流程讲解:
【当用户登录时获取当前用户所有权限放到session中,用户访问需要权限的页面时从session拿到这个用户并且拿到他拥有的权限,
判断URL在不在这个权限列表中如果在就通过,如果不在就直接在中间件进行返回,告诉他不能进行访问!】
6.跨域处理
jsonp: 巧妙利用scrpit标签进行处理
缺点:1.双方必须约定好函数, 2.只能发GET请求。
cors: 设置响应头,告诉浏览器不要拦截。[本地开发前后端分离项目的时候]
因为VUe的端口和rest-framework不一样,所以需要跨域。
真正上线后,vue会和后台是同一个域名,不会跨域。
7.ORM操作
- only - defer - seleted_related - prefetch_related
示例: class Depart(models.Model): 5个部门 title = models.CharField(...) class User(models.Model): 10个用户 name = models.CharField(...) email = models.CharField(...) dp = models.FK(Depart)
1.以前的你:11次单表查询
result = User.objects.all() for item in result: print(item.name,item.dp.title)
2. seleted_related,主动做连表查询(1次链表)[支持O2O,FK]
result = User.objects.all().seleted_related('dp') for item in result: print(item.name,item.dp.title)
问题:如果链表多,性能越来越差。
3. prefetch_related:2次单表查询 [支持O2O,FK,M2M]
# select * from user ; # 通过python代码获取:dp_id = [1,2] # select * from depart where id in dp_id result = User.objects.all().prefetch_related('dp') for item in result: print(item.name,item.dp.title)
补充:如果数据量比较大,不会使用FK,允许出现数据冗余,硬盘不值钱,用户体验最值钱。
8.restful以及相关源码
django rest-framework是干什么的?
快速搭建基于restful规范的接口。
你理解的restful规范!
restful是一个规范,规定API如何编写,通过他可以让我们API更加简介可维护。
10条基本【必会】
---method不同,
---https,
---面向资源,
---api,
---版本号,
---条件,
---返回值,
---状态码,
---错误信息,
---hymedia,
django-rest-framework
-认证:登录(设置Token值)
-频率:
[取到IP地址,ip为键,时间戳为值],取到最新的访问时间,
跟列表内的进行对比,把过期的剔除掉,如果新访问的剔
除不掉以前的表示访问过快,这样返回他不能进行继续访问]
面试技巧【掌握主动权】:
因为会有代理IP的存在,那么应该用登录用户来做这个,登录用户不能频繁的更换IP。
匿名用户不好做。(封禁代理IP,代理过多,没招!)
如果对方让你提一个需求,【匿名用户的话,取到电脑的MAC地址,这个貌似不能作假】
一般不要说做过这个频率访问的应用,应该是说自己近期看过源码。
建议
你可以提一些实现不了的方案,然后说这个好像也坐不了,反抛给他问他或者他们公司怎么去做的,或者有什么更好的方案?
一般情况下都是默认将访问记录放在缓存中,redis,memacached(访问十分的快)
匿名: 1.1.1.1 :[时间,时间,时间] 登录: user : [时间,时间,时间]
-权限
------
-序列化:
1.面向对象。构造方法是__init__,真正的构造方法是__new__【临时补充知识点】 many=True[ListSerializer对象] many=False[就是当前对象]
序列化根据many的不同进行判断然后去进行实例化。
-列表生成式:
[permisson() for permission in self.permission_class]
生成一个个的实例化对象