请求-响应过程
事件(Events)是一种让我们可以在Robyn 应用生命周期中执行特定逻辑的机制,Robyn 为应用程序周期和HTTP请求响应周期定义了四个标准事件,分别是startup
事件、shutdown
事件、before_request
事件、after_request
事件。通过这四个事件,我们可以进行应用程序级别或路由级别的程序扩展。在FastAPI中,这些扩展程序也被叫做中间件(middleware)。
应用启动、关闭事件
在 Robyn 中,应用启动、关闭事件常用于全局性的资源初始化、清理任务、集成监控等。
1、启动事件(Startup Events)
在服务器启动完成后执行,常用于初始化数据库连接、加载配置、启动后台任务等。有两种注册方式:
装饰器
@app.startup_handler
async def on_startup():
print("应用已启动!准备就绪")
绑定函数
async def on_startup():
print("应用已启动!")
app.startup_handler(on_startup)
2、关闭事件(Shutdown Events)
在服务关闭前执行,适合进行资源释放、断开连接、保存状态、清理日志等操作。
@app.shutdown_handler
def on_shutdown():
print("服务即将关闭,开始清理")
注意:在事件中同步函数可正常执行,但 async 版本可能有兼容问题,推荐使用同步函数以确保回调正常触发。
中间件
由于Robyn 没有提供与 FastAPI 类似的装饰器 @app.middleware
,也没有提供任何的内置中间件。因此,我们只能借助before_request
事件、after_request
事件来实现中间件的业务逻辑。在Robyn的内部实现中有一个结构叫作 middleware_router,用于管理中间件流程。
1、前置中间件(BeforeRequest)
前置中间件是在每次发起HTTP请求之前所执行的函数。它可以在请求处理之前修改请求对象或执行任何其他操作,可用于统一验证、限流、重写请求等。
@app.before_request("/")
async def hello_before_request(request: Request):
request.headers["before"] = "sync_before_request"
return request
2、后置中间件(AfterRequest)
后置中间件在路由函数处理完成后执行,用于统一处理响应对象,例如添加全局 Header、日志注入、缓存更新等。
@app.after_request("/*")
def add_header(response):
response.headers["X-Powered-By"] = "Robyn"
return response
后置中间件接收并返回 Response 对象,可进行链式修改。
3、示例:性能监控中间件
下面我们通过结合使用before_request
事件和after_request
事件,实现一个简单的性能监控中间件:
import time
from robyn import Robyn
app = Robyn(__file__)
@app.before_request
def timing_middleware(request):
request.start_time = time.time()
return request
@app.after_request
def timing_after_middleware(request, response):
duration = time.time() - request.start_time
print(f"{request.method} {request.url.path} - {duration:.3f}s")
response.headers["X-Response-Time"] = f"{duration:.3f}s"
return response
@app.get("/slow")
def slow_endpoint():
time.sleep(0.1) # Simulate work
return {"message": "slow response"}
错误处理
Robyn 提供了 @app.exception
装饰器,用于指定系统的异常处理函数,以拦截系统中出现的各种异常,我们可以为所有的异常返回统一格式的响应内容,也可以通过分析拦截到的异常信息返回有针对性的响应内容。
@app.exception
def handle_exception(error: Exception):
if error is NotFoundError:
return Response(
status_code=404,
description="Not Found",
headers={"Content-Type": "application/json"},
)
else:
return Response(
status_code=500,
description="Internal Server Error",
headers={"Content-Type": "application/json"}
)