django之中间件

django中间件简介

django是中间件的门户:
	当请求来的时候依次经过七个中间件然后再进入到后端,
	当响应走的时候依次反方向尽力七个中间件然后再返回到前端.

django默认的七个中间件
	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中间件:
django使用的是字符串导入的模式
而django中的字符串就是类的所在位置
from django.middleware.security import SecurityMiddleware
中间件的一些代码
class SessionMiddleware(MiddlewareMixin):
    def process_request(self, request):
        session_key = request.COOKIES.get(settings.SESSION_COOKIE_NAME)
        request.session = self.SessionStore(session_key)
    def process_response(self, request, response):
        return response
      
class CsrfViewMiddleware(MiddlewareMixin):
  	def process_request(self, request):
        csrf_token = self._get_token(request)
        if csrf_token is not None:
            # Use same token next time.
            request.META['CSRF_COOKIE'] = csrf_token
    def process_view(self, request, callback, callback_args, callback_kwargs):
        return self._accept(request)

    def process_response(self, request, response):
        return response
      
class AuthenticationMiddleware(MiddlewareMixin):
    def process_request(self, request):
        request.user = SimpleLazyObject(lambda: get_user(request))

django生命周期流程图

django之中间件_第1张图片

如何自定义中间件

1.在项目中创建一个任意名称的文件夹
2.在文件夹下创建一个任意名称的py文件
3.在该py文件内需要书写类(这个类必须继承MiddlewareMixin)
from django.utils.deprecation import MiddlewareMixin
	然后在这个类中定义五个方法
4.然后将路径定义注册到配置文件中

中间件的5个方法

在django的7个中间件的内容中都有process_request,process_resopnse方法

1.必须掌握的方法
1.1.process_response
	请求走的时候一定会经过每个中间件的process_response方法
	如果没有此方法就跳过
	执行顺序:按照在settings文件中组测的中间件顺序从下到上执行
	返回对象:该方法必须返回一个HttpResponse对象
		1.默认返回HTTPesponse方法
		2.返回一个自定义的HttpResponse方法
			(狸猫换太子)
	参数:该方法有两个参数
		requets,resopnse		
1.2.process_request
	请求来的时候一定会经过每个中间件的process_request方法
	如果没有则跳过
	执行顺序:按照在settings文件中注册的中间件从上到下顺序执行
	返回结果:如果在request请求中接收到了HttpResponse返回的三板斧,则会直接原路返回,不会执行后面的操作
	flask对比:flask框架中,即使在中间件中有返回也会执行完所有的流程
	该方法有一个参数:
	request
2.了解即可
2.1process_view
	参数:该方法的参数为 request,view_name,*args,**kwargs
	执行:在路由找到视图函数时并且在视图函数执行时触发
2.2process_template_response
	参数:request,response
	触发条件:只有当返回的HttpRespose对象中有render才可以触发
	def test(request):
    print("myapp 中的 index视图")

    def render():
        print("in index/render")
        return HttpResponse("OK")
    ret = HttpResponse("OK")
    ret.render = render
    return ret
2.3process_exception 
	参数:request,exception
    触发条件:在报错的时候触发此函数

实例

from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse

class MyMiddleware(MiddlewareMixin):
    def process_request(self, request):
        print('第一个中间件的request')
        # return HttpResponse('我返回了一个Http对象')

    def process_response(self, request, response):
        print('第一个中间件的response')
        return response


class MyMiddleware1(MiddlewareMixin):
    def process_request(self, request):
        print('第er个中间件的request')

    def process_response(self, request, response):
        print('第er个中间件的response')
        return response

    def process_view(self,request,view_name,*args,**kwargs):
        print(view_name, args, kwargs)
        print('这是view的内部')

    def process_template_response(self,request,response):
        print('这是template内部')
        return response


    def process_exception(self,request,exception):
        print('我是第二个中间件里面的process_exception')
        print(exception)

crsf 跨站请求伪造

实例:钓鱼网站

crsf的作用:
	网页在给用户返回一个能够直接提交数据表单页面的时候会给这个页面添加一个唯一标识符,如果符合标识符则数据可以提交到后台,正常执行如果不符合该标识符,则会(403 Forbidden)

如何符合crsf校验

1.在form表单中
{%crsf_token%}
<form action="" method="post">
    {% csrf_token %}
    <p>username:<input type="text" name="username"></p>
    <p>target_user:<input type="text" name="target_user"></p>
    <p>money:<input type="text" name="money"></p>
    <p><input type="submit"></p>
</form>
2.ajax提交符合crsf的三种方式
# ajax如何符合校验
// 第一种 利用标签查找获取页面上的随机字符串
{#data:{"username":'jason','csrfmiddlewaretoken':$('[name=csrfmiddlewaretoken]').val()},#}
ps:随机字符串的变量名必须是csrfmiddlewaretoken
// 第二种 利用模版语法提供的快捷书写
{#data:{"username":'jason','csrfmiddlewaretoken':'{{ csrf_token }}'},#}
// 第三种 通用方式直接拷贝js代码并应用到自己的html页面上即可
data:{"username":'jason'}
直接书写即可
<script src="{% static 'js/mysetup.js' %}"></script>

第三种方式js代码

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);
    }
  }
});

csrf相关装饰器

from django.utils.decorators import method_decorator

情况一:都不能访问,单单几个可以访问
第一种情况与CBV添加装饰器方法一致
@method_decorator(csrf_protect)  # 针对csrf_protect 第一种方式可以
@method_decorator(csrf_protect,name='post')  # 针对csrf_protect 第二种方式可以
@method_decorator(csrf_protect)  # 针对csrf_protect 第三种方式可以
情况二:都能访问,单单几个无法访问
第二种情况只能在 dispatch添加
@method_decorator(csrf_exempt)  # 针对csrf_exempt 第一种方式不可以
@method_decorator(csrf_exempt,name='post')  # 针对csrf_exempt 第二种方式不可以
 @method_decorator(csrf_exempt)  # 针对csrf_exempt 第三种方式可以
实例
from django.views.decorators.csrf import csrf_protect,csrf_exempt
from django.utils.decorators import method_decorator
"""
csrf_protect  需要校验
    针对csrf_protect符合我们之前所学的装饰器的三种玩法
csrf_exempt   忽视校验
    针对csrf_exempt只能给dispatch方法加才有效
"""
# @csrf_exempt
# @csrf_protect
def transfer(request):
    if request.method == 'POST':
        username = request.POST.get('username')
        target_user = request.POST.get('target_user')
        money = request.POST.get('money')
        print('%s给%s转了%s元'%(username,target_user,money))
    return render(request,'transfer.html')



from django.views import View

# @method_decorator(csrf_protect,name='post')  # 针对csrf_protect 第二种方式可以
# @method_decorator(csrf_exempt,name='post')  # 针对csrf_exempt 第二种方式不可以
@method_decorator(csrf_exempt,name='dispatch')
class MyCsrfToken(View):
    # @method_decorator(csrf_protect)  # 针对csrf_protect 第三种方式可以
    # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第三种方式可以
    def dispatch(self, request, *args, **kwargs):
        return super(MyCsrfToken, self).dispatch(request,*args,**kwargs)

    def get(self,request):
        return HttpResponse('get')

    # @method_decorator(csrf_protect)  # 针对csrf_protect 第一种方式可以
    # @method_decorator(csrf_exempt)  # 针对csrf_exempt 第一种方式不可以
    def post(self,request):
        return HttpResponse('post')

基于django中间件的编程思想

importlib模块简介

能够根据字符传文件路径找到py文件
但是这种方法最小只能找到py文件
import imoprtlib
res = 'core.a'
ret = importlib.import_module(res)

<module 'ccc.b' from 'E:\\360MoveData\\Users\\y7000\\Desktop\\day69\\common\\ccc\\b.py'>import导入的的结果一样

简单案例

settings

# coding:utf-8

paths = [
    'ccc.email.Email',
    'ccc.qq.QQ',
    'ccc.wechart.Wechat',
]
c包下
__init__ 核心
from common.settings import paths
import importlib
def send_all():
    for path in paths:
        approach, cls_name = path.rsplit('.',maxsplit=1)
        module = importlib.import_module(approach)
        cls = getattr(module, cls_name)
        obj = cls()
        obj.send()

email.py
# coding:utf-8
class Email(object):

    def send(self):
        print('你好啊')
 
email.py
# coding:utf-8
class Email(object):

    def send(self):
        print('你好啊')
 ...

思想总结

如果针对有很多对象有相似针对对象的功能可以使用鸭子类型来定义类
然后,importlib+反射的方式实现字符串导入,一键管理的方式
如上,首先将所有的对象路径放在列表当中
其次,在由于包导入的是__init__下的功能,创建__init__
然后再__init___中定义一个接口,将路径进行分割处理,运用importlib方式导入模块
然后运用反射在模块中找到所需要的的类,创建对象,调用方法,完成创建

你可能感兴趣的:(django)