Django Middleware 中间件
中间件字符串导入方式
settins.py -> MIDDLEWARE 中间件的放置位置
用户请求时,最先是从中间件,全部按顺序执行
中间件又有两种,接收和返回的
- 接收请求的中间件,request
- 返回请求的中间件, response
请求过来:
- 中间件:拦截一部分请求;比如验证session, 没有登录的 请求一些页面,跳转至登录页;(图片为中间件的请求过程.)
2 .再到 urls ,分发请求
3 .到views 视图 ,通过 CBV(dispatch反射) 和 FBV 的 get 请求 讲 template 页面渲染返回给用户; - 渲染之前 可以从数据库拿出数据,放到render 的参数里面传递过去, locals() 表示 把所有参数传递
还可以 实例化 其他 form 类,并渲染给前端
- 可以应用于:
- 请求日志
- 用户登录认证
- 各种跳转
- 防火墙
自定义中间件
settins.py -> MIDDLEWARE 先去注册到里面才可以应用
django 1.11 以后form djang.utils.deprecation import MiddlewareMixin
这个就没了,需要手动自己写到你的自定义的文件里去
settings.py
from django.middleware.common import CommonMiddleware
white_list = ['/login_demo/'] # 白名单机制, 不用验证session 信息 #中间件 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', 'md.middleware.MiddlewareLogin', # 注册 ]
自定义的 中间件 -> middleware.py
class MiddlewareMixin(object): def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__() def __call__(self, request): response = None if hasattr(self, 'process_request'): response = self.process_request(request) if not response: response = self.get_response(request) if hasattr(self, 'process_response'): response = self.process_response(request, response) return response #自己写的中间件需要 手动去继承它 MiddlewareMixin class Middleware_hc_login(MiddlewareMixin): def process_request(self, request): print ('你需要自定义的代码,写在这') if not request.META.get('PATH_INFO') in white_list: if not request.session.get('login'): return redirect('/login') def process_response(self, response): print ('这个是你的response返回,必须最后带上return返回') print ('一般可以不写这个response,只要写request就可以了') return response
白名单机制
white_list = ['/login'] # 如果是登录的话,这个白名单就不会判断session
if not request.META.get('PATH_INFO') in white_list: if not request.session.get('login'): return redirect('/login')
关于请求头部信息
Header 和 request.META
request.META 是一个Python字典,包含了所有本次HTTP请求的Header信息,比如用户IP地址和用户Agent(通常是浏览器的名称和版本号)。 注意,Header信息的完整列表取决于用户所发送的Header信息和服务器端设置的Header信息。
这个字典中几个常见的键值有:
HTTP_REFERER
进站前链接网页,如果有的话。 (请注意,它是REFERRER的笔误。)
HTTP_USER_AGENT
用户浏览器的user-agent字符串,如果有的话。 例如: "Mozilla/5.0 (X11; U; Linux i686; fr-FR; rv:1.8.1.17) Gecko/20080829 Firefox/2.0.0.17" .
REMOTE_ADDR
客户端IP,如:"12.345.67.89" 。(如果申请是经过代理服务器的话,那么它可能是以逗号分割的多个IP地址,如:"12.345.67.89,23.456.78.90" 。)
那么 request.META 里面还有什么有用的数据呢?动手写一个简单的view函数来显示 request.META 的所有数据,这样你就知道里面有什么了。
def display_meta(request): values = request.META.items() values.sort() html = [] for k, v in values: html.append('%s %s ' % (k, v)) return HttpResponse('%s
' % '\n'.join(html))
结果如下:
ALLUSERSPROFILE C:\ProgramData
APPDATA C:\Users\l3591\AppData\Roaming
COMMONPROGRAMFILES C:\Program Files\Common Files
COMMONPROGRAMFILES(X86) C:\Program Files (x86)\Common Files COMMONPROGRAMW6432 C:\Program Files\Common Files COMPUTERNAME HC COMSPEC C:\WINDOWS\system32\cmd.exe DJANGO_SETTINGS_MODULE hc_learning.settings DRIVERDATA C:\Windows\System32\Drivers\DriverData FPS_BROWSER_APP_PROFILE_STRING Internet Explorer FPS_BROWSER_USER_PROFILE_STRING Default HOMEDRIVE C: HOMEPATH \Users\l3591 LOCALAPPDATA C:\Users\l3591\AppData\Local LOGONSERVER \\HC NUMBER_OF_PROCESSORS 8 ONEDRIVE C:\Users\l3591\OneDrive ONLINESERVICES Online Services OS Windows_NT PATH D:\python3.7\Scripts\;D:\python3.7\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\iCLS\;C:\Program Files\Intel\Intel(R) Management Engine Components\iCLS\;C:\windows\system32;C:\windows;C:\windows\System32\Wbem;C:\windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files\Intel\Intel(R) Management Engine Components\DAL;C:\Program Files (x86)\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files\Intel\Intel(R) Management Engine Components\IPT;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files\Git\cmd;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\WINDOWS\System32\WindowsPowerShell\v1.0\;C:\WINDOWS\System32\OpenSSH\;C:\Program Files\Intel\WiFi\bin\;C:\Program Files\Common Files\Intel\WirelessCommon\;D:\python3\Scripts\;D:\python3\ PATHEXT .COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC PLATFORMCODE KV PROCESSOR_ARCHITECTURE AMD64 PROCESSOR_IDENTIFIER Intel64 Family 6 Model 142 Stepping 10, GenuineIntel PROCESSOR_LEVEL 6 PROCESSOR_REVISION 8e0a PROGRAMDATA C:\ProgramData PROGRAMFILES C:\Program Files PROGRAMFILES(X86) C:\Program Files (x86) PROGRAMW6432 C:\Program Files PSMODULEPATH C:\Program Files\WindowsPowerShell\Modules;C:\WINDOWS\system32\WindowsPowerShell\v1.0\Modules PUBLIC C:\Users\Public PYCHARM D:\pycharm\PyCharm 2018.3\bin; PYCHARM_HOSTED 1 PYCHARM_MATPLOTLIB_PORT 59802 PYTHON3 D:\python3.7\python.exe PYTHONIOENCODING UTF-8 PYTHONPATH C:\Users\l3591\Desktop\hc_learning;D:\pycharm\PyCharm 2018.3\helpers\pycharm_matplotlib_backend PYTHONUNBUFFERED 1 REGIONCODE APJ SESSIONNAME Console SYSTEMDRIVE C: SYSTEMROOT C:\WINDOWS TEMP C:\Users\l3591\AppData\Local\Temp TMP C:\Users\l3591\AppData\Local\Temp USERDOMAIN HC USERDOMAIN_ROAMINGPROFILE HC USERNAME hc USERPROFILE C:\Users\l3591 WINDIR C:\WINDOWS RUN_MAIN true SERVER_NAME hc GATEWAY_INTERFACE CGI/1.1 SERVER_PORT 8000 REMOTE_HOST CONTENT_LENGTH SCRIPT_NAME SERVER_PROTOCOL HTTP/1.1 SERVER_SOFTWARE WSGIServer/0.2 REQUEST_METHOD GET PATH_INFO /meta QUERY_STRING REMOTE_ADDR 127.0.0.1 CONTENT_TYPE text/plain HTTP_HOST 127.0.0.1:8000 HTTP_CONNECTION keep-alive HTTP_CACHE_CONTROL max-age=0 HTTP_UPGRADE_INSECURE_REQUESTS 1 HTTP_USER_AGENT Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0 HTTP_ACCEPT text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*'/'*;q=0.8 HTTP_ACCEPT_ENCODING gzip, deflate, sdch, br HTTP_ACCEPT_LANGUAGE zh-CN,zh;q=0.8 HTTP_COOKIE csrftoken=AOFQMm36wEvD2Y2TrPgnS4RhBWRo3kcic1UScGKDFZ7sUJDOQfGgBlX1HKqZY1CN wsgi.input <_io.BufferedReader name=996> wsgi.errors <_io.TextIOWrapper name='' mode='w' encoding='UTF-8'> wsgi.version (1, 0) wsgi.run_once False wsgi.url_scheme http wsgi.multithread True wsgi.multiprocess False wsgi.file_wrapper
解析客户端IP 并判断是否存在代理
通常访问者的IP就在其中,所以我们可以用下列方法获取用户的真实IP:
#X-Forwarded-For:简称XFF头,它代表客户端,也就是HTTP的请求端真实的IP,
#只有在通过了HTTP 代理或者负载均衡服务器时才会添加该项。
def get_ip(request): x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR') if x_forwarded_for: ip = x_forwarded_for.split(',')[0] #所以这里是真实的ip else: ip = request.META.get('REMOTE_ADDR')#这里获得代理ip return ip
扩展
中间件运用
-权限
-用户登录验证
-django的csrf_token 如何实现
csrf_token 验证在 process_view 方法里面
检查 视图是否被 @csrf_exempt (免除csrf认证)
去请求体 或 cookie 中获取token
两种 设置的方式
一种通过 装饰器
一种通过 中间件
1. process_request # 进
2. prrcess_view # 视图
3. process_response # 出
4. process_exception # 处理异常
5. process_render_template # 如果有template方法就会返回
请求流程
用户 -> process_request -> url路由匹配到了,但没执行 -> 跳转回中间件开头再从头走一遍到到 -> process_request -> 再到执行的views视图执行
执行完定义的逻辑 从 process_response 出去
如果中间有异常 会直接走 process_exception 处理返回异常
如果有template 就会走 process_render_template
from django.views.decorators.csrf import csrf_exempt, csrf_protect
@csrf_protect # 需要验证csrf_token认证
@csrf_exempt # 免除csrf_token认证