中间件和侦听器

中间件是在向服务器发出请求之前或之后执行的功能。它们可用于修改用户定义的处理程序函数的请求或响应。

此外,SANIC还提供了监听器,允许您在应用程序生命周期的不同点上运行代码。

中间件

中间件有两种类型:请求和响应。两者都使用@app.middleware decorator声明,decorator的参数是表示其类型的字符串:“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")

修改请求或响应

中间件可以修改给定的请求或响应参数,只要它不返回。下面的例子展示了一个实际的用例。

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.run(host="0.0.0.0", port=8000)

上面的代码将依次应用这三个中间件。第一个中间件添加密钥将向请求对象添加一个新的密钥foo。这是因为请求对象可以像dict对象一样被操作。然后,第二个中间件自定义_横幅会将HTTP响应头服务器更改为假服务器,最后一个中间件会添加HTTP头以防止跨站点脚本(XSS)攻击。这两个函数在用户函数返回响应后调用。

及早回应

如果中间件返回一个httpresponse对象,那么请求将停止处理并返回响应。如果在到达相关的用户路由处理程序之前请求出现这种情况,则永远不会调用该处理程序。返回响应还将阻止任何其他中间件的运行。

@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')

听众

如果要在服务器启动或关闭时执行启动/拆卸代码,可以使用以下侦听器:

  • before_server_start

  • after_server_start

  • before_server_stop

  • after_server_stop

这些侦听器在接受应用程序对象和Asyncio循环的函数上作为修饰符实现。

例如:

@app.listener('before_server_start')
async def setup_db(app, loop):
    app.db = await db_setup()

@app.listener('after_server_start')
async def notify_server_started(app, loop):
    print('Server successfully started!')

@app.listener('before_server_stop')
async def notify_server_stopping(app, loop):
    print('Server shutting down!')

@app.listener('after_server_stop')
async def close_db(app, loop):
    await app.db.close()

也可以使用register_listener方法注册侦听器。如果您在另一个模块中定义了监听器(除了在其中实例化应用程序的模块),这可能很有用。

app = Sanic()

async def setup_db(app, loop):
    app.db = await db_setup()

app.register_listener(setup_db, 'before_server_start')

如果您想在循环开始后安排一个后台任务运行,sanic提供了add_task方法以方便执行。

async def notify_server_started_after_five_seconds():
    await asyncio.sleep(5)
    print('Server successfully started!')

app.add_task(notify_server_started_after_five_seconds())

SANIC将尝试自动注入应用程序,并将其作为参数传递给任务:

async def notify_server_started_after_five_seconds(app):
    await asyncio.sleep(5)
    print(app.name)

app.add_task(notify_server_started_after_five_seconds)

或者您可以显式传递应用程序以获得相同的效果:

async def notify_server_started_after_five_seconds(app):
    await asyncio.sleep(5)
    print(app.name)

app.add_task(notify_server_started_after_five_seconds(app))
`