中间件

1.中间件

1.1 使用

  • 编写类,在类型定义:process_request、process_view、process_response
  • 中间件注册,在settings中的配置。

1.1.1 正常

image-20230716091532551

1.编写类

可以写在任意的目录:自定义的类、继承一个类(推荐)

from django.utils.deprecation import MiddlewareMixin

class KeLaMiddleware(MiddlewareMixin):

    def process_request(self, request):
        # request是请求相关所有的数据
        pass

    def process_view(self, request, view, *args, **kwargs):
        # request是请求相关所有的数据; view是试图函数; 路由参数*args, **kwargs
        pass

    def process_response(self, request, response):
        # request是请求相关所有的数据
        # response是试图函数返回的那个对象(封装了要返回到用户浏览器的所有数据)
        return response

2.注册

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',
    "utils.md.KeLaMiddleware"
]
# 动态导入 + 反射

3.测试

from django.utils.deprecation import MiddlewareMixin


class KeLaMiddleware(MiddlewareMixin):

    def process_request(self, request):
        print("KeLa.process_request")

    def process_view(self, request, view, *args, **kwargs):
        print("KeLa.process_view",view, *args, **kwargs)

    def process_response(self, request, response):
        print("KeLa.process_response")
        return response
from django.contrib import admin
from django.urls import path
from django.shortcuts import HttpResponse


def x1(request):
    print("视图.x1")
    return HttpResponse("x1")


def x2(request, v1):
    print("视图.x2", v1)
    return HttpResponse("x2")


urlpatterns = [
    path('admin/', admin.site.urls),
    path('x1/', x1),
    path('x2/<int:v1>/', x2),
]
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',
    "utils.md.KeLaMiddleware"
]

4.问题

  • 中间件的功能好像有点像装饰器【底层源码闭包】

  • 基于中间件可以做什么?

    • 根据请求周期,对 request 进行赋值,后续方便进行调用。

    • 根据请求周期,对业务逻辑代码进行自定义,决定是否可以继续向后

      • return None,继续向后走

      • return HttpResponse对象

        return HttpResponse("...")
        return render("...")        ->   HttpResponse("...")
        return JsonReponse("...")   ->   HttpResponse("...")
        
    • 根据请求周期,对返回给用户浏览器的数据进行自定义:删除内容、增加、cookie、响应头...

  • 这个中间件和nginx apache这样的中间件概念一样吗?比如做前置代理,做https

    Django中间件  /  拦截器  / RequestHanler
    
  • 中间件可以跨语言调用吗?比如别人不是用python 写的,但是可以给我们的django 项目用?

    Django中间件
    	...
    架构中间件:
    	Django + redis(C语言)
    
  • 中间件只要两层,不要中间那个process.riew行不行,是不是有些特定场合需要返回最后一层

    ...
    
  • 那Django内置的中间件完成了些什么功能?

    ...
    

1.1.2 “不正常”

image-20230716091818839

如果用户向我的网站请求时,如果访问URL:

  • /x1/
  • /x2/
  • /x3/ ,比如携带凭证token,有凭证继续,无凭证返回无权访问。
http://127.0.0.1:8000/x2/12/
http://127.0.0.1:8000/x2/12/?xxx=123

http://127.0.0.1:8000/x3/?token=12938791923981723123
from django.utils.deprecation import MiddlewareMixin
from django.shortcuts import HttpResponse


class KeLaMiddleware(MiddlewareMixin):

    def process_request(self, request):
        # request.path_info
        # print(request.path_info,"KeLa.process_request")
        if request.path_info == "/x3/":
            token = request.GET.get('token')
            if token == "12938791923981723123":
                return
            else:
                return HttpResponse("无权访问")

如果用户向我的网站请求时,如果访问URL:

  • /x1/

  • /x2/ ,比如携带凭证token,有凭证继续,无凭证返回无权访问。

    x2/<int:v1>/', x2
    
    http://127.0.0.1:8000/x1/10/
    http://127.0.0.1:8000/x1/20/
    http://127.0.0.1:8000/x1/11/
    
  • /x3/


class KeLaMiddleware(MiddlewareMixin):

    def process_request(self, request):
        # request.path_info
        # print(request.path_info,"KeLa.process_request")
        # 以x2开头 或 正则   /x2/1111/   /x2/10/
        # if request.path_info == "/x2/":
        if request.path_info.startswith("/x2/"):
            token = request.GET.get('token')
            if token == "12938791923981723123":
                return
            else:
                return HttpResponse("无权访问")
class KeLaMiddleware(MiddlewareMixin):

    def process_view(self, request, view, *args, **kwargs):
        # request.path_info
        # print(request.path_info,"KeLa.process_request")
        url_name = request.resolver_match.url_name
        if url_name == "x2":
            token = request.GET.get('token')
            if token == "12938791923981723123":
                return
            else:
                return HttpResponse("无权访问")

关于自定义prcess_response,一般用于对请求要返回的数据进行修改。

class KeLaMiddleware(MiddlewareMixin):

    def process_response(self, request, response):
        response["xx"] = "wupeiqi"
        return response

答疑

  • Settings 里面的中间件有多个组件,那运行项目时的执行顺序是怎样的?是执行完这些中间件再执行路由匹配吗?后面写的中间件是不是要对前面的中间件功能非常清楚才行、避免可能功能覆盖带来bug?
  • 這邊定義的響應頭在用戶下一次訪問的時候會帶上麽
  • js可以读到content的内容吗
  • 刚才讲的这个response返回值的修改,增加了一个“xx”=“wupeiqi”,这种操作应该也可以增加的request请求头里面吧,那request增加的,是不是就和爬虫里面的某些js逆向参数,就是从这里来的?

1.2 使用(几乎不用)

  • 编写类,在类型定义:process_request、process_view、process_response、process_exception、process_template_response

    process_exception,视图函数有异常,处理出现异常时
    process_template_response,对于视图函数返回内容渲染扩展。
    	- 在视图函数中如果返回的对象内部有一个render方法且可以被调用执行
    	- process_template_response返回response参数(返回值)
    	- 在自定义的MyReponse的render方法中必须返回HttpRespose
    
  • 中间件注册,在settings中的配置。

class KeLaMiddleware(MiddlewareMixin):

    def process_exception(self, request, exception):
        print(request)
        print(exception, type(exception))
        return HttpResponse("错误了")
def x1(request):
    print("视图.x1")
    return HttpResponse("x1")
class MyHttpResponse:
    def __init__(self, body):
        self.body = body

    def render(self):
        return HttpResponse(self.body)  # 真正的返回


def x1(request):
    print("视图.x1")
    return MyHttpResponse("x1")
class KeLaMiddleware(MiddlewareMixin):

    def process_template_response(self, request, response):
        return response

def x1(request):
    print("视图.x1")
    return HttpResponse("源代码-x1")


def x2(request, v1):
    return HttpResponse("源代码-x2")


def x3(request):
    return HttpResponse("源代码-x3")


class MyHttpResponse:
    def __init__(self, body):
        self.body = body

    def render(self):
        return HttpResponse(self.body)


def x1(request):
    print("视图.x1")
    return MyHttpResponse("x1")


def x2(request, v1):
    return MyHttpResponse("x2")


def x3(request):
    return MyHttpResponse("x3")

class KeLaMiddleware(MiddlewareMixin):

    def process_template_response(self, request, response):
        response.body = f"源代码-{response.body}"
        return response

1.3 源码

1.关于请求

image-20230716111119343

from wsgiref.simple_server import make_server


def run_server(environ, start_response):
    # 只要请求到来,就会走这里的代码
    # 1.根据请求 environ 进行后续业务处理
    # 2.返回内容。。。
    start_response('200 OK', [('Content-Type', 'text/html')])
    return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]


if __name__ == '__main__':
    httpd = make_server('127.0.0.1', 8000, run_server)  # # 有请求到来时,执行  obj(environ, start_response)
    httpd.serve_forever()
from wsgiref.simple_server import make_server

class Handler:
    
    def __init__(self):
        # 做一些初始化动作
        self.name = "wupeiqi"
        
	
    def __call__(self,environ, start_response):
        # 根据初始化的动作,去执行...
        # ...
        start_response('200 OK', [('Content-Type', 'text/html')])
    	return [bytes('<h1>Hello, web!</h1>', encoding='utf-8'), ]


if __name__ == '__main__':
    obj = Handler() # 执行 
    httpd = make_server('127.0.0.1', 8000, obj)  # 有请求到来时,执行 obj(environ, start_response)
    httpd.serve_forever()

image-20230716112505648

2.启动Django项目WSGIHandler.__init__

image-20230716121612821

image-20230716121637108

3.请求到来WSGIHandler.__call__

流程:中间件的执行、路由匹配、视图函数的执行。

小结

  • 1.7.x源码,底层实现,是基于好几个列表。

  • 4.x源码,

    函数的作用域 + 闭包 + 装饰器
    面向对象 + __call__方法
    
    # 核心
    # handler = SecurityMiddleware对象
    #             __call__
    #                process_request
    #                get_reponse = SessionMiddleware对象
    #                process_response 
    #                              __call__
    #                                   process_request 
    #                                   get_reponse = CommonMiddleware对象
    #                                   process_response
    #                                                 __call__
    #                                                     process_request
    #                                                     get_reponse = KeLaMiddleware对象
    #                                                     process_response
    
posted @ 2024-09-12 16:32  Sherwin_szw  阅读(1)  评论(0编辑  收藏  举报