中间件功能实现的目的就是为了改变全局的请求与响应。比如说需要对访问流量的限制或者是全局请求合法性的验证。如下图所示 : 客户端请求发送过来之后会进入请求中间件,如果请求中间件拦截成功,那么直接向客户端返回被拦截的响应,否则进入请求转发的流程处理之后将响应提交给响应中间件处理之后返回。
那么在轻量级Web框架中如何设计中间件的接口?首先了解一下,请求过来之后的流程 : 请求进入之后首先走的是__call__
函数,携带系统信息跳转到applications
中的application
方法,在该方法中调用了dispatch_request
方法完成了的请求的转发并返回了客户端的响应。所以中间件添加在application
中最合适不过。
from werkzeug.wrappers import Request
from middlewares import handle_request_middleware,handle_response_middleware
def application(app,environ,start_response) :
request = Request(environ)
result = handle_request_middleware(app,request)
if result is None :
response = app.dispatch_request(request)
else :
response = result
return response(environ,start_response)
result = handle_response_middleware(app,response)
if result is not None :
response = result
return response(environ,start_response)
上述示例代码展示了中间件在请求与响应过程中位置,但是却没有涉及到中间件的配置,事实上,请求中间件和响应中间件是一组中间件的集合,当所有请求中间件未被拦截成功的时候才会进入请求转发的流程中。上述示例代码中handle_request_middleware
以及handle_response_middleware
就是用来处理请求中间件以及响应中间件的函数,代码如下 :
def handle_request_middleware(app,request):
for i in range(len(app.request_middlewares)) :
func = app.request_middlewares[i]
result = func(request)
if result is not None :
return result
def handle_response_middleware(app,response) :
for j in range(len(app.response_middlewares)-1,-1,-1) :
func = app.response_middlewares[j]
result = func(response)
if response is not None :
return result
在项目启动的时候就需要将已经配置在settings中中间件注册到项目中,往项目中注册的中间件的形式以及中间件的编写形式:
class CounterMiddleWare :
#访问量计数中间件
@staticmethod
def process_request(request) :
pass
@staticmethod
def process_response(response):
pass
def _register_request_middleware(app,process_request) :
app.request_middlewares.append(process_request)
def _register_response_middleware(app,process_response) :
app.response_middlewares.append(process_response)
def setter_register_middleware(app) :
from settings import MiddleWarelist
for middleware in MiddleWarelist :
_register_request_middleware(app,getattr(middleware, 'process_request'))
_register_response_middleware(app,getattr(middleware,'process_response'))
注册的形式就是将指定的方法注册到项目中保存在列表中,通过遍历列表完成对中间件集合的访问。
测试用例 :
- 中间件对全局请求的拦截
测试用例 : 访问http://127.0.0.1:8000的时候,添加中间件前浏览器反馈Hello World 页面,添加中间件拦截之后,浏览器反馈Request Has Been Head Off 页面。
测试反馈 :
未添加中间件 :
添加中间件 :
class CounterMiddleWare :
@staticmethod
def process_request(request) :
from werkzeug.wrappers import Response
return Response('<h1 align=center>Request Has Been Head Off </h1>',content_type='text/html',status=401)
@staticmethod
def process_response(response):
pass
2. 测试中间件对流量访问的限制
测试用例 :统计页面的访问流量,通过redis保存,当访问流量超过规定的阈值的时候,访问http:127.0.0.1:8000页面返回Request Has Been Head Off。
class CounterMiddleWare :
#访问量计数中间件
@staticmethod
def process_request(request) :
import redis
redisConnect = redis.Redis(host='localhost',port=6379)
if redisConnect.exists(request.host_url):
redisConnect.incr(name=request.host_url,amount=1)
else :
redisConnect.set(name=request.host_url,value=1)
@staticmethod
def process_response(response):
pass
class AccessContorlMiddleWare :
#权限校验中间件
@staticmethod
def process_request(request):
from werkzeug.wrappers import Response
import redis
redisConnect = redis.Redis(host='localhost', port=6379)
if int(redisConnect.get(name=request.host_url)) >= 10 :
return Response('<h1 align=center>Request Has Been Head Off </h1>',content_type='text/html',status=401)
@staticmethod
def process_response(response):
pass