准确测量耗时应使用process_view记开始、process_response记结束,并将时间存于request对象;避免全局变量、threading.local或缓存;高频请求需采样、过滤探针接口、异步上报;异步中间件须用async def并继承basemiddleware,禁用阻塞日志。

中间件里怎么拿到请求开始和结束时间
关键不是“记录”,而是“准确测量耗时”——Django中间件的 process_request 和 process_response 不在同一个请求线程生命周期内被调用(尤其启用异步视图后),直接存全局变量或类属性会出错。正确做法是在 process_request 中把起始时间写进 request 对象本身:
def process_request(self, request):
request._start_time = time.time()
然后在 process_response 里读取它:
def process_response(self, request, response):
if hasattr(request, '_start_time'):
duration = time.time() - request._start_time
# 记录日志或发到监控系统
注意:不要用 threading.local() 或缓存,Django 请求对象本身就是每个请求独享的。
为什么 process_view 比 process_request 更适合计时
因为 process_request 在 URL 解析前就执行,包含 WSGI 层开销、中间件自身初始化等噪声;而 process_view 在路由匹配完成、视图函数即将执行时触发,process_response 在视图返回响应后执行——这二者之间才真正反映业务逻辑耗时。
-
process_request→ 可能含反向代理头解析、CSRF 预处理等非业务开销 -
process_view→ 视图函数还没跑,但 request 已完备(GET/POST 已解析、user 已认证) - 推荐组合:
process_view记开始,process_response记结束
如何避免日志爆炸和性能拖累
高频 API(比如每秒上千请求)如果每条都写磁盘日志,IO 会成为瓶颈,甚至拖慢整个响应。实际部署中必须加采样和过滤:
- 只记录耗时 > 500ms 的慢请求:
if duration > 0.5: - 对 GET /health、/metrics 等探针接口跳过记录:
if request.path in ['/health', '/metrics']: - 用异步方式发耗时数据(如发到 Redis 队列或 StatsD),别阻塞主线程
- 避免在日志里拼接完整
request.body(可能含敏感字段且大体积),改用len(request.body)或仅记 method + path + status
异步视图下中间件要怎么写才不丢时间
Django 4.1+ 支持异步中间件,但普通同步中间件在 async view 场景下仍会被调用——此时 process_request 是 sync,process_response 却可能在 async context 中执行,time.time() 依然可用,但要注意:
- 不能在中间件里 await 任何东西(除非你写的是
__acall__异步中间件) - 异步中间件必须同时实现
__call__和__acall__,否则 Django 会降级为同步调用 - 更稳妥的做法:统一用
async def process_request+async def process_response,并确保中间件类继承自BaseMiddleware(Django 4.2+ 推荐)
最易忽略的一点:异步中间件里别用 logging.info() 直接打日志——某些 logging handler(如 RotatingFileHandler)是阻塞的,会拖垮整个 event loop。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











