应使用__call__方法而非仅process_request+process_response,在其中用time.perf_counter()记录起止时间并存于request._start_time,确保异常路径不漏统计;耗时写入响应头需用标准命名(如x-response-time)、ascii键名、字符串值且保留3位小数;上报必须异步,避免阻塞请求。

Middleware里怎么记录请求开始和结束时间
关键是在 process_request 里记下 time.time(),在 process_response(或 process_exception)里再取一次,相减就是耗时。Django 2.0+ 推荐用新式中间件类写法,必须实现 __call__ 方法,这样能确保无论是否异常都执行结束逻辑。
- 别只依赖
process_request+process_response,漏掉 500 错误会丢失数据;__call__是唯一可靠入口 - 时间戳用
time.perf_counter()比time.time()更准,不受系统时间跳变影响 - 把计时器存到
request对象上(如request._start_time = perf_counter()),避免闭包或全局变量引发并发问题
如何把耗时信息安全地附加到响应头里
直接往 response 的 headers 写就行,但要注意:HTTP 头名必须是 ASCII 字符,且不能含空格或下划线;值要转成字符串并限制长度,防止超长头被网关截断或拒绝。
- 推荐用
X-Response-Time或X-Process-Time这类标准命名,避免自定义前缀引发 CDN/代理过滤 - 耗时建议保留 3 位小数(单位秒),比如
f"{elapsed:.3f}",既够精度又不冗余 - 如果项目启用了 Gzip 或其他压缩中间件,确保你的中间件注册顺序在它们之前,否则头可能被覆盖
怎样避免监控逻辑拖慢正常请求
耗时统计本身开销极小,真正风险在于后续上报——比如同步发 HTTP 请求、写文件、调用数据库。这些必须异步或节流处理,否则会把整个请求链拖垮。
- 绝对不要在中间件里调用
requests.post()上报指标;改用线程池(concurrent.futures.ThreadPoolExecutor)或消息队列(如 Celery) - 高频接口(如健康检查
/health)建议白名单过滤,用request.path.startswith("/health")直接跳过计时 - 日志记录也得设阈值,比如只对 >1000ms 的请求打 DEBUG 日志,避免日志爆炸
Django配置和注册时容易踩的坑
中间件注册顺序决定执行时机,位置错了会导致计时不全或头被覆盖。Django 默认中间件列表里,SecurityMiddleware 和 CommonMiddleware 都可能修改响应头,你的监控中间件得比它们更靠前。
- 在
MIDDLEWARE列表里,把它放在django.middleware.security.SecurityMiddleware之后、django.middleware.common.CommonMiddleware之前 - 别忘了在
settings.py中启用USE_TZ = True,否则带时区的日志时间可能错乱(虽然不影响计时,但排查问题时很麻烦) - 本地开发用
DEBUG=True时,Django 自带的调试面板也会统计耗时,注意区分中间件打的头和调试面板显示的数值是否一致
process_response,只有 __call__ 能兜底。还有就是生产环境反向代理(Nginx / ALB)可能重写或删除自定义响应头,得确认代理配置是否透传 X-* 头。大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!











