django中间件类似其他框架的拦截器 中间件过滤所有请求和响应
python# handler
class WSGIHandler(base.BaseHandler):
request_class = WSGIRequest
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.load_middleware() # 加载中间件
def __call__(self, environ, start_response):
set_script_prefix(get_script_name(environ))
signals.request_started.send(sender=self.__class__, environ=environ)
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
# wsgi.py 入口
application = WSGIHandler() #
django 就是app, app需要可以调用。所以实例可以调用就是__call__
方法调用。
而在call之前,已经实例化了,注意上面的实例化会执行, 先self传递到父类实例化。然后在当前子类中进行实例化 加载中间件 self.load_middleware()
django中间件salary/settings.py
pythonMIDDLEWARE = [
'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',
]
来回不一样的中间件处理
https://docs.djangoproject.com/en/3.2/
Middleware: Overview | Built-in middleware classes
def simple_middleware(get_response): # One-time configuration and initialization. def middleware(request): # Code to be executed for each request before # the view (and later middleware) are called. response = get_response(request) # Code to be executed for each request/response after # the view is called. return response return middleware
类 1.10之后,就有这样的类了, 语法变了。内核不变
class SimpleMiddleware: def __init__(self, get_response): self.get_response = get_response # One-time configuration and initialization. def __call__(self, request): # Code to be executed for each request before # the view (and later middleware) are called. response = self.get_response(request) # Code to be executed for each request/response after # the view is called. return response
使用1.8文档 https://docs.djangoproject.com/en/1.8/topics/http/middleware/
During the request phase, before calling the view, Django applies middleware in the order it’s defined in MIDDLEWARE_CLASSES
, top-down. Two hooks are available:
During the response phase, after calling the view, middleware are applied in reverse order, from the bottom up. Three hooks are available:
process_exception()
(only if the view raised an exception)process_template_response()
(only for template responses)process_response()
If you prefer, you can also think of it like an onion: each middleware class is a “layer” that wraps the view.
The behavior of each hook is described below.
注意以上的方法,是 process_request()
在每个中间件上 处理完成之后,再由 process_view()
在每个中间件上处理。
这2个函数,就是在每个中间件上有这2个勾子函数,框架在特定的点上留了一些加载点,如果你挂了一个勾子函数,框架运行时,路过这个中间件,看是否有挂勾子函数,有我就执行一下。
当前版本,只是形式变了, process_request和process_response不存在了,但是内在不变。
回到 https://docs.djangoproject.com/en/3.2/
new出一个包在项目根目录, utils。准备一个文件 utils/middlewares.py
pythonclass Middleware1:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
# 1次性生成, load_middleware()时会实例化所有中间件。
print(self.__class__.__name__, ' 初始化')
def __call__(self, request): # 处理请求和响应
# Code to be executed for each request before the view (and later middleware) are called.
# 解析请求后到视图函数之前
print(self.__class__.__name__, ' 等价于call--process_request勾子 解析请求后到视图函数之前')
response = self.get_response(request) # 向洋葱里面钻,直到handler, 再逐层进入
# Code to be executed for each request/response after the view is called.
# 视图函数返回响应之后,构建响应前
print(self.__class__.__name__, ' 等价于call--process_response勾子 视图函数返回响应之后,构建响应前')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后,view操作前处理')
print(self.__class__.__name__,'process_view[', view_func,']', '视图函数 fn(request, *args, **kwargs)')
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后, view处理之后处理')
class Middleware2:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
# 1次性生成, load_middleware()时会实例化所有中间件。
print(self.__class__.__name__, ' 初始化')
def __call__(self, request): # 处理请求和响应
# Code to be executed for each request before the view (and later middleware) are called.
# 解析请求后到视图函数之前
print(self.__class__.__name__, ' 等价于call--process_request勾子 解析请求后到视图函数之前')
response = self.get_response(request) # 向洋葱里面钻,直到handler, 再逐层进入
# Code to be executed for each request/response after the view is called.
# 视图函数返回响应之后,构建响应前
print(self.__class__.__name__, ' 等价于call--process_response勾子 视图函数返回响应之后,构建响应前')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后,view操作前处理')
print(self.__class__.__name__,'process_view[', view_func,']','视图函数 fn(request, *args, **kwargs)')
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后, view处理之后处理')
copy middleware中 copy reference
pythonMIDDLEWARE = [
'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.middlewares.Middleware1',
'utils.middlewares.Middleware2',
]
# 重启服务 Django version 3.2.8, using settings 'salary.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK. Middleware2 初始化 Middleware1 初始化
返向初始化,load_middeware有一个revert()
实际上中间件 完成之后由处理视图. 包装过程就是 m2先包装handler, 再m1. 所以请求来了,先m1处理,m2处理。响应后,先m2处理,后m1处理。
参考 5.1的洋葱模型
从上到下,就是洋葱模型的从外到内 先初始化从内到外(列表从下到上) 请求由外到内(列表从上到下)。响应从内到外(列表从下到上)
请求test函数的get方法 http://127.0.0.1:8000/emps/
pythonMiddleware2 初始化
Middleware1 初始化
[13/May/2022 15:51:25] "GET /emps/ HTTP/1.1" 200 33
Middleware1 等价于call--process_request勾子 解析请求后到视图函数之前 # M1 进入 response = self.get_response(request)
Middleware2 等价于call--process_request勾子 解析请求后到视图函数之前 # M2 进入 response = self.get_response(request)
Middleware1 等价于call--process_view勾子 处理完 process_request之后,view操作前处理 # 进入view
Middleware1 process_view[ <function test at 0x000001644E6F7F70> ] 视图函数 fn(request, *args, **kwargs)
Middleware1 等价于call--process_view勾子 处理完 process_request之后, view处理之后处理
Middleware2 等价于call--process_view勾子 处理完 process_request之后,view操作前处理 # 进入view
Middleware2 process_view[ <function test at 0x000001644E6F7F70> ] 视图函数 fn(request, *args, **kwargs)
Middleware2 等价于call--process_view勾子 处理完 process_request之后, view处理之后处理
# 进入到handler
<WSGIRequest: GET '/emps/'>
{}
# 响应
Middleware2 等价于call--process_response勾子 视图函数返回响应之后,构建响应前 # 响应 M2
Middleware1 等价于call--process_response勾子 视图函数返回响应之后,构建响应前 # 响应 M1
diff+from django.http import JsonResponse
class Middleware1:
def __call__(self, request): # 处理请求和响应
# Code to be executed for each request before the view (and later middleware) are called.
# 解析请求后到视图函数之前
print(self.__class__.__name__, ' 等价于call--process_request勾子 解析请求后到视图函数之前')
+ return JsonResponse({'a': 1, 'b': [1,3,5]})
response = self.get_response(request) # 向洋葱里面钻,直到handler, 再逐层进入
这样,在middleware处理请求,就不会向内钻了。 请求 http://127.0.0.1:8000/emps/ 无论什么方法
[13/May/2022 16:07:16] "PUT /emps/ts2 HTTP/1.1" 200 24 Middleware1 等价于call--process_request勾子 解析请求后到视图函数之前
这样无论什么路由, 什么方法, 直接就反弹回客户端。
M1不加return, M2加return
diff+from django.http import JsonResponse
class Middleware2:
def __call__(self, request): # 处理请求和响应
# Code to be executed for each request before the view (and later middleware) are called.
# 解析请求后到视图函数之前
print(self.__class__.__name__, ' 等价于call--process_request勾子 解析请求后到视图函数之前')
+ return JsonResponse({'a': 1, 'b': [1,3,5]})
response = self.get_response(request) # 向洋葱里面钻,直到handler, 再逐层进入
请求 http://127.0.0.1:8000/emps/ 无论什么方法
Middleware2 初始化 Middleware1 初始化 [13/May/2022 16:03:55] "PUT /emps/ts2 HTTP/1.1" 200 24 Middleware1 等价于call--process_request勾子 解析请求后到视图函数之前 # M1 request处理 Middleware2 等价于call--process_request勾子 解析请求后到视图函数之前 # M2 request处理,直接返回,跳过process_view, view function. 直接到自己前一个中间件的response Middleware1 等价于call--process_response勾子 视图函数返回响应之后,构建响应前 # M1就是M2前一个中间件的response
说明M2返回时,会跳到M1 response = self.get_response(request)
之后
return JsonResponse({'a': 1, 'b': [1,3,5]}) response = self.get_response(request) # 向洋葱里面钻,直到handler, 再逐层进入
注意
response = self.get_response(request)
之前提前return时
process_view均处理完,return None
均返回None, 最终可以到达 view函数。
如果process_view提前返回时,将从最后一个中间件开始处理响应
difffrom django.http import JsonResponse
class Middleware1:
def process_view(self, request, view_func, view_args, view_kwargs):
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后,view操作前处理')
print(self.__class__.__name__,'process_view[', view_func,']', '视图函数 fn(request, *args, **kwargs)')
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后, view处理之后处理')
# return None # 默认行为 下一个process_view
+ return JsonResponse({'test': 'm1.processview'})
现在请求 http://127.0.0.1:8000/emps/ 无论什么方法
python# 初始化
Middleware2 初始化
Middleware1 初始化
# request处理完
Middleware1 等价于call--process_request勾子 解析请求后到视图函数之前 # M1
Middleware2 等价于call--process_request勾子 解析请求后到视图函数之前 # M2
# 处理M1的view提前return 非None
Middleware1 等价于call--process_view勾子 处理完 process_request之后,view操作前处理
Middleware1 process_view[ <function test at 0x0000017B6E8A7F70> ] 视图函数 fn(request, *args, **kwargs)
Middleware1 等价于call--process_view勾子 处理完 process_request之后, view处理之后处理
# 直接跳过view函数,来到响应
Middleware2 等价于call--process_response勾子 视图函数返回响应之后,构建响应前
Middleware1 等价于call--process_response勾子 视图函数返回响应之后,构建响应前
process_request走完之后,可以通过路由,可以知道谁是view
utils/middlewares.py
difffrom django.http import JsonResponse,HttpResponse
class Middleware1:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
# 1次性生成, load_middleware()时会实例化所有中间件。
print(self.__class__.__name__, ' 初始化')
def __call__(self, request): # 处理请求和响应
# Code to be executed for each request before the view (and later middleware) are called.
# 解析请求后到视图函数之前
print(self.__class__.__name__, ' 等价于call--process_request勾子 解析请求后到视图函数之前')
response:HttpResponse = self.get_response(request) # 向洋葱里面钻,直到handler, 再逐层进入
# Code to be executed for each request/response after the view is called.
# 视图函数返回响应之后,构建响应前
print(self.__class__.__name__, ' 等价于call--process_response勾子 视图函数返回响应之后,构建响应前')
+ response.headers['X-MY'] = 'songliangcheng'
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后,view操作前处理')
print(self.__class__.__name__,'process_view[', view_func,']', '视图函数 fn(request, *args, **kwargs)')
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后, view处理之后处理')
# return None # 默认行为 下一个process_view
return None
class Middleware2:
def __init__(self, get_response):
self.get_response = get_response
# One-time configuration and initialization.
# 1次性生成, load_middleware()时会实例化所有中间件。
print(self.__class__.__name__, ' 初始化')
def __call__(self, request): # 处理请求和响应
# Code to be executed for each request before the view (and later middleware) are called.
# 解析请求后到视图函数之前
print(self.__class__.__name__, ' 等价于call--process_request勾子 解析请求后到视图函数之前')
response = self.get_response(request) # 向洋葱里面钻,直到handler, 再逐层进入
# Code to be executed for each request/response after the view is called.
# 视图函数返回响应之后,构建响应前
print(self.__class__.__name__, ' 等价于call--process_response勾子 视图函数返回响应之后,构建响应前')
return response
def process_view(self, request, view_func, view_args, view_kwargs):
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后,view操作前处理')
print(self.__class__.__name__,'process_view[', view_func,']', '视图函数 fn(request, *args, **kwargs)')
print(self.__class__.__name__, ' 等价于call--process_view勾子 处理完 process_request之后, view处理之后处理')
return None
响应头就有自己的东西
settings.py定义中间件列表,初始化反向初始化,包粽子从里到外,访问里从外到里,就是列表正向访问。
先处理 从外到内 process_request, 再处理 从外到内 process_view, 再处理view, 最后处理 从内到外 process_response.
process_request:
IP,参数,检查请求。
ip分析 过滤统计,useragent分析 过滤统计
合格通过,不合格, 直接响应。
process_response:
python'django.contrib.sessions.middleware.SessionMiddleware', # 从request.COOKIE中获取sessionid, 查数据库表,获取此sid对应的信息。#request.session=创建Session类的实例。
'django.contrib.auth.middleware.AuthenticationMiddleware', # 通过session中间件提供的sessionid, 获取到userid, 通过uid查表获取user, 否则就是匿名用户。
#request.user=要么是user实例或匿名用户实例。
在pycharm中,选中 django.contrib.sessions.middleware.SessionMiddleware
按2下shift
就会搜索字符,查找到内建的类
request到达视图函数时,已经经过上面两个中间件,所以request上一定有这2个属性session, user
本文作者:mykernel
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!