中间件是在服务器接受请求之前或之后执行的函数。它们用于修改传递给路由处理函数的
request
,或是由处理函数生成的
response
对象。
中间件类型
中间件有两种类型:
request
和
response
,都是通过
@app.middleware
修饰器来声明的,以修饰器的字符串参数
request
或
response
来表示这两种类型。
请求中间件只接受
request
对象作为参数。
响应中间件同时接受
request
和
response
两个对象作为参数。
下面是一个最简单的中间件的例子,它没有改变request和response,只是打印了信息:
@app.middleware('request')
async def print_on_request(request):
print("I print when a request is received by the server")
@app.middleware('response')
async def print_on_response(request, response):
print("I print when a response is returned by the server")
修改request或response
中间件可以修改作为参数传递的request或response,但不需要返回它们,参见下面的例子:
from sanic import Sanic
from sanic import response
app = Sanic(__name__)
@app.middleware('request')
async def add_key(request):
# Add a key to request object like dict object
request['foo'] = 'bar'
@app.middleware('response')
async def custom_banner(request, response):
response.headers["Server"] = "Fake-Server"
@app.middleware('response')
async def prevent_xss(request, response):
response.headers["x-xss-protection"] = "1; mode=block"
@app.route('/')
async def home(request):
return response.text(request['foo'])
app.run(host="127.0.0.1", port=8888, debug=True)
上面的代码将按顺序应用3个中间件。第一个中间件
add_key
给
request
对象增加了一个新的键
foo
,这样可以工作是因为
request
对象可以像字典那样被操作。
第二个中间件
custom_banner
修改了HTTP响应的头,把
Server
设置成
Fake-Server
。
最后一个中间件
prevent_xss
添加了响应头以防止跨站点脚本(XSS)攻击。
response类型的中间件在路由处理函数(比如,本例中的
home()
返回
response
后被调用。
使用
curl
访问上面代码的链接:
curl -i http://127.0.0.1:8888
我们可以看到:
HTTP/1.1 200 OK
Connection: keep-alive
Keep-Alive: 5
x-xss-protection: 1; mode=block
Server: Fake-Server
Content-Length: 3
Content-Type: text/plain; charset=utf-8
bar
提前响应
这里的“提前”是指中间件直接返回
HTTPResponse
对象,这时请求将停止处理并返回response。如果这发生在request类型的中间件,路由处理函数将不会被调用。返回response将阻止后续的中间件继续执行。
比如:
@app.middleware('request')
async def halt_request(request):
return text('I halted the request')
@app.middleware('response')
async def halt_response(request, response):
return text('I halted the response')
因为中间件
halt_request
返回了
Response
对象,其后续的中间件
halt_response
就不会被执行。