0
点赞
收藏
分享

微信扫一扫

django框架的使用及其梳理系列四

中间件

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

from django.utils.deprecation import MiddlewareMixin

class TempMiddleware(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

注册

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"
]
# 动态导入 + 反射

views.py

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),
]

效果:

django框架的使用及其梳理系列四_数据

作用

基于中间件可以做什么?

  • 根据请求周期,对 request 进行赋值,后续方便进行调用。
  • 根据请求周期,对业务逻辑代码进行自定义,决定是否可以继续向后
  • return None,继续向后走
  • return HttpResponse对象

根据请求周期,对返回给用户浏览器的数据进行自定义:删除内容、增加、cookie、响应头...

注意

这个中间件和nginx apache这样的中间件不一样。比如做前置代理,做https

Django中间件  /  java的拦截器  / c#的RequestHanler

比如我们做一个token限制,需要传参token才能访问:

    #md.py
    def process_request(self, request):
        # request是请求相关所有的数据
        if request.path_info == "/xxx/":
            token = request.GET.get("token")
            if token == "qwe123":
                return
            return HttpResponse("permission error!!!")


#views.py

def xxx(request):
    return HttpResponse("succeed")

urlpatterns = [
    path('admin/', admin.site.urls),
    path('x1/', x1),
    path('x2/<int:v1>/', x2),
    path('xxx/', xxx),
]

django框架的使用及其梳理系列四_中间件_02


django框架的使用及其梳理系列四_数据_03

中间件源码

从uwsgi点到basehandler:

django框架的使用及其梳理系列四_中间件_04

load_middleware:

异步的部分删除了

    def load_middleware(self, is_async=False):
        """
        Populate middleware lists from settings.MIDDLEWARE.

        Must be called after the environment is fixed (see __call__ in subclasses).
        """
        #列表存放中间件的方法
        self._view_middleware = []
        self._template_response_middleware = []
        self._exception_middleware = []

        #闭包,函数->内部调用
        handler = convert_exception_to_response(get_response)
        

django框架的使用及其梳理系列四_中间件_05

[inner(), self._get_response]

#翻转获取的中间件
for middleware_path in reversed(settings.MIDDLEWARE):
            middleware = import_string(middleware_path)

try:
                # Adapt handler, if needed.
                adapted_handler = self.adapt_method_mode(
                    middleware_is_async, handler, handler_is_async,
                    debug=settings.DEBUG, name='middleware %s' % middleware_path,
                )
                mw_instance = middleware(adapted_handler)
                #自动执行类中的call方法
            except MiddlewareNotUsed as exc:
                if settings.DEBUG:
                    if str(exc):
                        logger.debug('MiddlewareNotUsed(%r): %s', middleware_path, exc)
                    else:
                        logger.debug('MiddlewareNotUsed: %r', middleware_path)
                continue
            else:
                handler = adapted_handler
                
                
                if mw_instance is None:
                raise ImproperlyConfigured(
                    'Middleware factory %s returned None.' % middleware_path
                )
                #判断是否存在指定方法
            if hasattr(mw_instance, 'process_view'):
                self._view_middleware.insert(
                    0,
                    self.adapt_method_mode(is_async, mw_instance.process_view),
                )
            if hasattr(mw_instance, 'process_template_response'):
                self._template_response_middleware.append(
                    self.adapt_method_mode(is_async, mw_instance.process_template_response),
                )
            if hasattr(mw_instance, 'process_exception'):
                # The exception-handling stack is still always synchronous for
                # now, so adapt that way.
                self._exception_middleware.append(
                    self.adapt_method_mode(False, mw_instance.process_exception),
                )
              handler = convert_exception_to_response(mw_instance)

中间件的请求到来:

class WSGIHandler(base.BaseHandler):
        #请求的封装
        request = self.request_class(environ)
        response = self.get_response(request)
		#中间件+路由匹配+视图函数
        response._handler_class = self.__class__
		#响应码
        status = '%d %s' % (response.status_code, response.reason_phrase)
        response_headers = [
            *response.items(),
            *(('Set-Cookie', c.output(header='')) for c in response.cookies.values()),
        ]
        start_response(status, response_headers)
        if getattr(response, 'file_to_stream', None) is not None and environ.get('wsgi.file_wrapper'):
            # If `wsgi.file_wrapper` is used the WSGI server does not call
            # .close on the response, but on the file wrapper. Patch it to use
            # response.close instead which takes care of closing all files.
            response.file_to_stream.close = response.close
            response = environ['wsgi.file_wrapper'](response.file_to_stream, response.block_size)
        return response
		
#get_response		
   def get_response(self, request):
        #触发 self._middleware_chain=handler 
		#逐步执行中间件的process_request注册顺序,从前到后
		#执行self._get_response[路由匹配]
		#中间件的process_view,视图函数,中间件的process_exception,
		#中间件的process_template_response
		
		
		#中间件中的process_response按照中间件的注册顺序,从后到前
        response = self._middleware_chain(request)
        response._resource_closers.append(request.close)
        if response.status_code >= 400:
            log_response(
                '%s: %s', response.reason_phrase, request.path,
                response=response,
                request=request,
            )
        return response


#_get_response

    def _get_response(self, request):
        response = None
		#路由匹配
		#callback=视图函数 callback_args, callback_kwargs 动态路由传递的参数
		#request.resolve_match()
        callback, callback_args, callback_kwargs = self.resolve_request(request)
        #执行中间件所有的process_view
        for middleware_method in self._view_middleware:
            response = middleware_method(request, callback, callback_args, callback_kwargs)
            if response:
                break

        if response is None:
		    #django内部数据库支持的事务
            wrapped_callback = self.make_view_atomic(callback)
            try:
			    #调用视图函数
                response = wrapped_callback(request, *callback_args, **callback_kwargs)
            except Exception as e:
			    #调用中间件处理视图函数的异常
                response = self.process_exception_by_middleware(e, request)
                if response is None:
                    raise

        # 给出报错
        self.check_response(response, callback)

        #执行process_template_response
        if hasattr(response, 'render') and callable(response.render):
            for middleware_method in self._template_response_middleware:
                response = middleware_method(request, response)
            try:
                response = response.render()
            except Exception as e:
                response = self.process_exception_by_middleware(e, request)
                if response is None:
                    raise

        return response

举报

相关推荐

0 条评论