中间件
1.中间件
1.1 使用
- 编写类,在类型定义:process_request、process_view、process_response
- 中间件注册,在settings中的配置。
1.1.1 正常
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 “不正常”
如果用户向我的网站请求时,如果访问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.关于请求
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()
2.启动Django项目WSGIHandler.__init__
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
本文作者:Sherwin
本文链接:https://www.cnblogs.com/sherwin1995/p/18410525
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步