Python学习第148天(Django中间层)
官方解释
中间件是一个用来处理Django的请求和响应的框架级别的钩子。它是一个轻量、低级别的插件系统,用于在全局范围内改变Django的输入和输出。每个中间件组件都负责做一些特定的功能。
通俗解释
说的直白一点中间件是帮助我们在视图函数执行之前和执行之后都可以做一些额外的操作,它本质上就是一个自定义类,类中定义了几个方法,Django框架会在请求的特定的时间去执行这些方法。
二.中间件有什么用
中间件类似Django后端的保安,能够帮我实现,网站全局的身份验证,黑名单,白名单,权限校验,访问频率限制,反爬相关 >>> django用来帮你全局相关的功能校验
补充:'只要是涉及到全局的校验你都可以在中间件中完成'
注意:'由于其影响的是全局,所以需要谨慎使用,使用不当会影响性能。'
查看中间件:
打开Django项目的Settings.py文件,看到的MIDDLEWARE配置项及为中间件(7个默认的)。
MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.SessionMiddleware', 'django.middleware.common.CommonMiddleware', 'django.middleware.csrf.CsrfViewMiddleware', 'django.contrib.auth.middleware.AuthenticationMiddleware', 'django.contrib.messages.middleware.MessageMiddleware', 'django.middleware.clickjacking.XFrameOptionsMiddleware', ]
三.自定义中间件
django中间件中有五个用户可以自定义的方法.
自定义中间件步骤:
1.新建一个任意名字的文件夹,在该文件夹内键一个任意名字的py文件 2.自定义的中间件类要继承: MiddlewareMixin from django.utils.deprecation import MiddlewareMixin 3.在settings.py文件中的MIDDLEWARE内注册自定义的中间件类
<1> process_request() 方法 (*)
from django.utils.deprecation import MiddlewareMixin class MyMdd1(MiddlewareMixin): def process_request(self, request): print('自定义中间件 process_request 方法一') class MyMdd2(MiddlewareMixin): def process_request(self, request): print('自定义中间件 process_request 方法二') class MyMdd3(MiddlewareMixin): def process_request(self, request): print('自定义中间件 process_request 方法三') ''' 类中的request里包含了前端请求来所携带的所有信息(是个字典),我们可以通过request完成一些操作 '''
总结:
1.请求来的时候 会经过每个中间件里面的process_request方法(从上往下) 2.如果该方法里面直接返回了HttpResponse对象,那么会直接返回,不再往下执行 '''基于该特点就可以做访问频率限制,身份校验,权限校验''' (它的返回值可以是None也可以是HttpResponse对象。返回值是None的话,按正常流程继续走,
交给下一个中间件处理,如果是HttpResponse对象,Django将不执行视图函数,而将相应对象返回给浏览器。)
<2>process_response() 方法 (*)
class MyMdd1(MiddlewareMixin): def process_response(self,request,response): print('自定义中间件 process_response 方法一') return response class MyMdd2(MiddlewareMixin): def process_response(self,request,response): print('自定义中间件 process_response 方法二') return response class MyMdd3(MiddlewareMixin): def process_response(self,request,response): print('自定义中间件 process_response 方法三') return response
总结:
1.必须将response形参返回,因为这个形参指代的就是要返回给前端的数据 2.响应走的时候,会依次经过每一个中间件里面的process_response方法(从下往上)
process_request 与 process_response图片总结(借大神照片)
<3>process_view() 方法
def process_view(self,request,view_func,view_args,view_kwargs): print(view_func) # 视图函数的内存地址 print(view_args) # 是将传递给视图的位置参数的列表. print(view_kwargs) # 是将传递给视图的关键字参数的字典 print('中间件里面的process_view方法')
借一张大神的照片
总结:
1.路由匹配成功执行视图之前自动触发(从上往下依次执行) 2.它应该返回None或一个HttpResponse对象。 如果返回None,Django将继续处理这个请求,
执行任何其他中间件的process_view方法,然后在执行相应的视图。 如果它返回一个HttpResponse对象,
那么将不会执行Django的视图函数,而是直接在中间件中掉头,倒叙执行一个个process_response方法,
最后返回给浏览器
<4>process_exception() 方法
def index(request): print('我是index视图函数') def render(): return HttpResponse('什么鬼玩意') obj = HttpResponse('index') obj.render = render return obj
再次借一张大神的照片
总结:
1.当视图函数报错了,自动触发(从下往上依次执行)
<5> process_template_response() 方法
总结:
1.当你返回的HttpResponse对象中必须包含render属性才会触发
csrf跨站请求伪造
可以理解为 csrf 随机生成了一个字符串,放到前端,当前端是post请求的时候,会在先在
'django.middleware.csrf.CsrfViewMiddleware' 中间件内校验该字符串,若不一致,直接拒绝(403) 该随机字符串有两个特点: 1.同一个浏览器每一次访问都不一样 2.不同浏览器绝对不会重复
一.form表单中如何跨站请求伪造
<form action="" method="post"> {% csrf_token %} </form>
二.ajax发送post请求 如何避免csrf校验
<1>方法一
1.先在页面上写{% csrf_token %},利用标签查找,获取到该input键值信息 data:{'username':'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()}
<2>方法二(*)
直接书写'{{ csrf_token }}' data:{'username':'jason','csrfmiddlewaretoken':'{{ csrf_token }}'}
<3>方法三(**)
<!--思路:你可以将该获取随机键值对的方法写到一个js文件中,将该js文件放到static问价夹内,之后只需要导入该文件即可(注意别忘了静态文件配置)--> 1.{% load static %} <script src="{% static 'setjs.js' %}"></script> 2.正常书写ajax即可
function getCookie(name) { var cookieValue = null; if (document.cookie && document.cookie !== '') { var cookies = document.cookie.split(';'); for (var i = 0; i < cookies.length; i++) { var cookie = jQuery.trim(cookies[i]); // Does this cookie string begin with the name we want? if (cookie.substring(0, name.length + 1) === (name + '=')) { cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); break; } } } return cookieValue; } var csrftoken = getCookie('csrftoken'); function csrfSafeMethod(method) { // these HTTP methods do not require CSRF protection return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method)); } $.ajaxSetup({ beforeSend: function (xhr, settings) { if (!csrfSafeMethod(settings.type) && !this.crossDomain) { xhr.setRequestHeader("X-CSRFToken", csrftoken); } } }); js文件内容
三.csrf_exempt 与 csrf_protect 装饰器
1.当网站全局都需要校验csrf, 有几个不需要校验该如何处理?
2.当你网站全局不校验csrf, 有几个需要校验又该如何处理?
<1>FBV:
from django.views.decorators.csrf import csrf_exempt,csrf_protect @csrf_exempt # 不校验csrf def index1(request): return HttpResponse('ok') @csrf_protect # 校验csrf def index2(request): return HttpResponse('ok')
<2>CBV:
from django.utils.decorators import method_decorator from django.views.decorators.csrf import csrf_exempt,csrf_protect # 这两个装饰器在给CBV装饰的时候 有一定的区别 1.如果是csrf_protect 那么有三种方式: # 第一种方式 # @method_decorator(csrf_protect,name='post') # 有效的 class MyView(View): # 第三种方式 # @method_decorator(csrf_protect) def dispatch(self, request, *args, **kwargs): res = super().dispatch(request, *args, **kwargs) return res def get(self,request): return HttpResponse('get') # 第二种方式 # @method_decorator(csrf_protect) # 有效的 def post(self,request): return HttpResponse('post') 2.如果是csrf_exempt 只有两种(只能给dispatch装) 特例 @method_decorator(csrf_exempt,name='dispatch') # 第二种可以不校验的方式 class MyView(View): # @method_decorator(csrf_exempt) # 第一种可以不校验的方式 def dispatch(self, request, *args, **kwargs): res = super().dispatch(request, *args, **kwargs) return res def get(self,request): return HttpResponse('get') def post(self,request): return HttpResponse('post')
以上是今天的内容,中间层总算总结清楚了。