day65中间件
昨日内容回顾
1 cookie
由于HTTP协议 是无状态的,所以没有办法保持会话,基于这种情况,浏览器发展出了cookie技术,通过cookie就能完成持续对话,大致过程就是类似一个字典的东西,从客户端浏览器访问服务的时候,带着这个字典,name后端服务器就能够身份认证的标识或者一些其他的信息,放到cookie里面,供客户端使用,并且以后客户端再来访问服务器就会一
直带着这个cookie,后端就客户端认证就可以从cookie里面的数据进行认证,从而完成保持会话的功能。
1.1 django 操作cookie的方法
request.COOKIES[key]
request.COOKIES.get(key)
request.COOKIES.get_signed_cookie(key,salt='xxx')
request.COOKIES.set
ret = HttpResponse('xx')
ret.set_cookie(key,value,)
ret.set_signed_cookie(key,value,salt='xxx')
2 session
面试问你session,从http,cookie那里开始说
密文加密,前端没法看。不直接给,一大堆随机的字符串,通过随机字符串,找到后端需要的信息。
把客户端的信息存入到硬盘里
request.session[key1] = value1
1. 生成一个随机字符串 sessionid = adagadga
2. key1:value1,key2:value2 --- 加密 放到djangosesssion表中 加密后的数据 过期日期(14天),一个用户对应一个浏览器,就有一条session记录
3. 设置cookie,将随机字符串(那个钥匙) sessionid放到cookie里
ret.set_cookie(session,随机字符串,)
查询:
request.session[key1]
request.session(key1)
删除:
request.session.flush() session表 cookiedou'ya都要删
day65
0 jquery 操作cookie
$.cookie('sessionid') 查看,无法查看这个的值
$.cookie('csrftoken')
$.cookie('name',111) 设置值
0.1 7层协议
从上到下:应表会传网数物
1 中间件
1.1 定义
前面已经学习了给视图函数加装饰器来判断用户是否登陆,把没有登录的用户请求跳转到登录页面。但是以后添加的视图函数可能也需要加上装饰器,这样是不是稍微有点繁琐。
def wrapper(func):
def inner(*args, **kwargs):
start_time = time.time()
ret = func(*args, **kwargs)
end_time = time.time()
print("used:", end_time-start_time)
return ret
return inner
# FBV版添加班级
@wrapper
def add_class(request):
if request.method == "POST":
class_name = request.POST.get("class_name")
return redirect("/class_list/")
return render(request, "add_class.html")
定义:
中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出。因为改变的是全局,所以需要谨慎实用,用不好会影响到性能。
如果你想修改请求,例如被传送到view中的HttpRequest对象。 或者你想修改view返回的HttpResponse对象,这些都可以通过中间件来实现。
是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。
中间的五个方法
process_request(self,request) # 请求来的时候,过中间件会自动执行的方法,正常的话,return None,异常的话直接可以回复HttpResponse对象,顺序从上至下执行
process_view(self, request, view_func, view_args, view_kwargs) #顺序从下往上倒叙的,任意一个其他方法里面如果出现了return一个HttpResponse对象,那么就会不执行其他内容了,而是直接执行各个中间件的process_response方法,如果自己的中间件里面有process_response 这个方法,会先执行它自己的。如果自己的中间件里面有process_response这个方法,直接返回
process_template_response(self,request,response) #url分发之后,视图 执行之前,执行,从下到上正序的
process_exception(self, request, exception) #视图函数报错了,会执行,顺序倒序的
process_response(self, request, response)
wsgi 封装了socket 按着http协议接解包:request
一层一层过中间件 request
反着走一遍中间件 response做加工
以上方法的返回值可以是None或一个HttpResponse对象,如果是None,则继续按照django定义的规则向后继续执行,如果是HttpResponse对象,则直接将该对象返回给用户。
当用户发起请求的时候会依次经过所有的的中间件,这个时候的请求时process_request,最后到达views的函数中,views函数处理后,在依次穿过中间件,这个时候是process_response,最后返回给请求者。
process_request
Django 写法
from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
def process_request(self, request):
print("MD1里面的 process_request")
class MD2(MiddlewareMixin):
def process_request(self, request):
print("MD2里面的 process_request")
pass
request 有return就不走后面的了:
process_request
process_request有一个参数,就是request,这个request和视图函数中的request是一样的。
它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。
总结
中间件的process_request方法是在执行视图函数之前执行的。
当配置多个中间件时,会按照MIDDLEWARE中的注册顺序,也就是 列表的 索引 值,从前到后依次执行的。
不同中间件之间传递的request都是同一个对象
process_response
它有两个参数,一个是request,一个是response,request就是上述例子中一样的对象,response是视图函数返回的HttpResponse对象。该方法的返回值也必须是HttpResponse对象。
setting配置中间件
MIDDLEWARE = ['middlewares.MD1', # 自定义中间件MD1,这个写的是你项目路径下的一个路径,例如,如果你放在项目下,文件夹名成为utils,那么这里应该写utils.middlewares.MD1
'middlewares.MD2' # 自定义中间件MD2
]
from django.utils.deprecation import MiddlewareMixin
class MD1(MiddlewareMixin):
def process_request(self, request):。。
#不必须写return值
def process_response(self, request, response):#request和response两个参数必须有,名字随便取
print("MD1里面的 process_response")
#print(response.__dict__['_container'][0].decode('utf-8'))
#查看响应体里面的内容的方法,或者直接使用response.content也可以看到响应体里面的内容,由于response是个变量,直接点击看源码是看不到的,你打印type(response)发现是HttpResponse对象,查看这个对象的源码就知道有什么方法可以用
return response #必须有返回值,写return response ,这个response就像一个接力棒一样
#return HttpResponse('瞎搞') ,如果你写了这个,那么你视图返回过来的内容就被它给替代了
class MD2(MiddlewareMixin):
def process_request(self, request):。。。
def process_response(self, request, response):
print("MD2里面的 process_response")
return response #必须返回response,不然你上层的中间件就没有拿到httpresponse对象,就会报错
request 有return就不走后面的了
1的请求
2的请求
md2的响应
md1的响应 、
并发量比较大的网站
限制访问频率,(防止爬虫死循环(每一分钟可访问))4
IP地址 外网地址,局域网的都一样。 request.META.get('REMOTE_ADDR') # IP地址 # 换ip地址也可以访问,不单单会访问频率,
尝试一下通过中间件来控制用户的访问次数,让用户在10秒不能访问我的网站超过3次。
ip1 : [8:55,8:53,8:51] 10秒以内
再来事件: now()
now()- 8:51 > 10
len(dic['ip1']) >=3
统计mac地址,打电话获取,不好获取
process_view
process_view(self, request, view_func, view_args, view_kwargs)
该方法有四个参数
request是HttpRequest对象。
view_func是Django即将使用的视图函数。 (它是实际的函数对象,而不是函数的名称作为字符串。)
view_args是将传递给视图的位置参数的列表.
view_kwargs是将传递给视图的关键字参数的字典。 view_args和view_kwargs都不包含第一个视图参数(request)。
和上述返回一样,有则返回,不走下面(无走)
def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD1 中的process_view")
print(view_func, view_func.__name__) #就是url映射到的那个视图函数,也就是说每个中间件的这个process_view已经提前拿到了要执行的那个视图函数
#ret = view_func(request) #提前执行视图函数,不用到了上图的试图函数的位置再执行,如果你视图函数有参数的话,可以这么写 view_func(request,view_args,view_kwargs)
#return ret #直接就在MD1中间件这里这个类的process_response给返回了,就不会去找到视图函数里面的这个函数去执行了。
def process_view(self, request, view_func, view_args, view_kwargs):
print("-" * 80)
print("MD2 中的process_view")
print(view_func, view_func.__name__)
process_view方法是在process_request之后,reprocess_response之前,视图函数之前执行的,执行顺序按照MIDDLEWARE中的注册顺序从前到后顺序执行的
process_exception
process_exception(self, request, exception)
该方法两个参数:
一个HttpRequest对象
一个exception是视图函数异常产生的Exception对象。
这个方法只有在视图函数中出现异常了才执行,它返回的值可以是一个None也可以是一个HttpResponse对象。如果是HttpResponse对象,Django将调用模板和中间件中的process_response方法,并返回给浏览器,否则将默认处理异常。如果返回一个None,则交给下一个中间件的process_exception方法来处理异常。它的执行顺序也是按照中间件注册顺序的倒序执行。
def process_exception(self, request, exception):
print(exception)
print("MD1 中的process_exception")
return HttpResponse(str(exception)) # 返回一个响应对象
def process_exception(self, request, exception):
print(exception)
print("MD2 中的process_exception")
如果视图函数中无异常,process_exception方法不执行。
想办法,在视图函数中抛出一个异常:
def index(request):
print("app01 中的 index视图")
raise ValueError("呵呵")
return HttpResponse("O98K")
输出结果
MD2里面的 process_request
## MD1里面的 process_request
MD2 中的process_view
## <function index at 0x0000022C09727488> index
MD1 中的process_view
<function index at 0x0000022C09727488> index
app01 中的 index视图
呵呵
MD1 中的process_exception
MD1里面的 process_response
MD2里面的 process_response
注意,这里并没有执行MD2的process_exception方法,因为MD1中的process_exception方法直接返回了一个响应对象。
process_template_response(用的比较少)
process_template_response(self, request, response)
它的参数,一个HttpRequest对象,response是TemplateResponse对象(由视图函数或者中间件产生)。
process_template_response是在视图函数执行完成后立即执行,但是它有一个前提条件,那就是视图函数返回的对象有一个render()方法(或者表明该对象是一个TemplateResponse对象或等价方法)。
view .py 中
def index(request):
print("app01 中的 index视图")
#raise ValueError('出错啦')
def render():
print("in index/render")
#raise ValueError('出错啦') #至于render函数中报错了,那么会先执行process_template_response方法,然后执行process_exception方法,如果是在render方法外面报错了,那么就不会执行这个process_template_response方法了。
return HttpResponse("O98K") #返回的将是这个新的对象
rep = HttpResponse("OK")
rep.render = render
return rep
混合类:各种继承