詳解django自定義中間件處理
中間件是一個(gè)鉤子框架,它們可以介入 Django 的請(qǐng)求和響應(yīng)處理過(guò)程。 它是一個(gè)輕量級(jí)、底層的 插件 系統(tǒng),用于在 全局修改 Django 的輸入或輸出 。
每個(gè)中間件組件負(fù)責(zé)完成某個(gè)特定的功能
這里介紹的中間件方法適用于 Django1.10 以上
相關(guān)文件: django middleware
Django基礎(chǔ)中間件
django.utils.deprecation.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
以上為Django基礎(chǔ)中間件源碼,要習(xí)慣于看源碼,上面的這段代碼并不復(fù)雜,下面我們來(lái)一一解釋。
def __init__(self, get_response=None): self.get_response = get_response super(MiddlewareMixin, self).__init__()
熟悉 python 類的都不陌生 __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
__call__
為每個(gè)請(qǐng)求/響應(yīng)執(zhí)行的代碼
self.process_request(request)
為每個(gè)請(qǐng)求到調(diào)用視圖之前的操作,通常可以在這里做一些用戶請(qǐng)求頻率的控制。
self.get_response(request)
為調(diào)用視圖
self.process_response(request, response)
為調(diào)用視圖完成后的操作
自定義中間件
剛才了解了基礎(chǔ)中間件,現(xiàn)在就開(kāi)始編寫我們自己的中間件。
通常我們回去繼承基礎(chǔ)中間件來(lái)實(shí)現(xiàn)自己的功能
from django.utils.deprecation import MiddlewareMixin class PermissionMiddlewareMixin(MiddlewareMixin): """ django 中間件 """ def process_request(self, request): pass def process_response(self, request, response): return response
如果你要在請(qǐng)求之前做處理,需要定義 process_request() 方法,去實(shí)現(xiàn)相關(guān)功能
如果你要在視圖調(diào)用之后做處理,需要定義 process_response() 方法,去實(shí)現(xiàn)相關(guān)功能
:warning:注意 定義 process_response() 方法一定要 return response
需要將你編寫的中間件添加到 settings 中的 MIDDLEWARE 里
我這里寫了一個(gè)通過(guò)中間件限制客戶端請(qǐng)求頻率,有興趣的可以看一下
django中間件客戶端請(qǐng)求頻率限制
通過(guò)redis lua腳本對(duì)客戶端IP請(qǐng)求頻率限制
# coding:utf-8 __author__ = 'carey@akhack.com' from django.utils.deprecation import MiddlewareMixin from django.http.response import HttpResponse from django_redis import get_redis_connection from hashlib import md5 class RequestBlockMiddlewareMixin(MiddlewareMixin): """ django中間件客戶端請(qǐng)求頻率限制 """ limit = 4 # 單位時(shí)間內(nèi)允許請(qǐng)求次數(shù) expire = 1 # 限制時(shí)間 cache = "default" # 獲取django cache def process_request(self, request): num = self.set_key(request) if num > self.limit: return HttpResponse("請(qǐng)求頻率過(guò)快,請(qǐng)稍后重試", status=503) @staticmethod def get_ident(request): """ Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR if present and number of proxies is > 0. If not use all of HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR. """ NUM_PROXIES = 1 xff = request.META.get('HTTP_X_FORWARDED_FOR') remote_addr = request.META.get('REMOTE_ADDR') num_proxies = NUM_PROXIES if num_proxies is not None: if num_proxies == 0 or xff is None: return remote_addr addrs = xff.split(',') client_addr = addrs[-min(num_proxies, len(addrs))] return client_addr.strip() return ''.join(xff.split()) if xff else remote_addr def get_md5(self, request): """ 獲取IP md5值 :param request: :return: """ ip_str = self.get_ident(request) ip_md5 = md5() ip_md5.update(ip_str.encode("utf-8")) return ip_md5.hexdigest() def set_key(self, request): """ 通過(guò)redis lua腳本設(shè)置請(qǐng)求請(qǐng)求次數(shù)和限制時(shí)間 :param request: :return: 限制時(shí)間內(nèi)請(qǐng)求次數(shù) """ lua = """ local current current = redis.call("incr",KEYS[1]) if tonumber(current) == 1 then redis.call("expire",KEYS[1],ARGV[1]) end return tonumber(redis.call("get", KEYS[1])) """ key = self.get_md5(request) redis_cli = get_redis_connection(self.cache) data = redis_cli.eval(lua, 1, key, self.expire, self.limit) return data
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Python開(kāi)發(fā)必知必會(huì)標(biāo)識(shí)符UUID全面使用指南
在Python編程中,UUID(通用唯一標(biāo)識(shí)符)是一個(gè)非常有用的工具,用于生成唯一的標(biāo)識(shí)符,本文將深入探討Python中UUID的用法、不同版本的UUID、以及如何在實(shí)際應(yīng)用中充分利用UUID的優(yōu)勢(shì)2023-12-12python庫(kù)-dotenv包?及?.env配置文件詳解
python-dotenv 能將配置文件的配置信息自動(dòng)加入到環(huán)境變量。 python-dotenv解決了代碼與敏感信息的分離,這篇文章主要介紹了python庫(kù)-dotenv包?|?.env配置文件,需要的朋友可以參考下2022-08-08matplotlib.pyplot畫圖并導(dǎo)出保存的實(shí)例
今天小編就為大家分享一篇matplotlib.pyplot畫圖并導(dǎo)出保存的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-12-12使用python求解迷宮問(wèn)題的三種實(shí)現(xiàn)方法
關(guān)于迷宮問(wèn)題,常見(jiàn)會(huì)問(wèn)能不能到達(dá)某點(diǎn),以及打印到達(dá)的最短路徑,下面這篇文章主要給大家介紹了關(guān)于如何使用python求解迷宮問(wèn)題的三種實(shí)現(xiàn)方法,需要的朋友可以參考下2022-03-03使用pandas把某一列的字符值轉(zhuǎn)換為數(shù)字的實(shí)例
今天小編就為大家分享一篇使用pandas把某一列的字符值轉(zhuǎn)換為數(shù)字的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2019-01-01Python+wxPython實(shí)現(xiàn)自動(dòng)生成PPTX文檔程序
這篇文章主要介紹了如何使用 wxPython 模塊和 python-pptx 模塊來(lái)編寫一個(gè)程序,用于生成包含首頁(yè)、內(nèi)容頁(yè)和感謝頁(yè)的 PPTX 文檔,感興趣的小伙伴可以學(xué)習(xí)一下2023-08-08用Python按時(shí)間分割txt文件中的數(shù)據(jù)方法步驟
這篇文章主要給大家介紹了如何用Python按時(shí)間分割txt文件中的數(shù)據(jù)的方法步驟,文中通過(guò)代碼示例給大家講解的非常詳細(xì),對(duì)大家學(xué)習(xí)Python處理txt文件有一定的幫助,需要的朋友可以參考下2023-12-12python實(shí)現(xiàn)的一個(gè)p2p文件傳輸實(shí)例
這篇文章主要介紹了python實(shí)現(xiàn)的一個(gè)p2p文件傳輸實(shí)例,文中用來(lái)解決多臺(tái)服務(wù)器維護(hù)文件同步問(wèn)題,需要的朋友可以參考下2014-06-06