因为request.headers是只读的Headers对象,修改无效;真正生效的是WSGI environ字典中的HTTP_*键(如HTTP_USER_AGENT),须通过WSGI中间件在请求进入Flask前修改environ。

为什么直接在 Flask 视图里改 request.headers 不生效?
因为 request.headers 是只读的 werkzeug.datastructures.Headers 对象,任何赋值或 add() 操作都会被忽略。真正起作用的请求头,在 WSGI 环境字典 environ 里 —— 比如 HTTP_USER_AGENT、HTTP_X_FORWARDED_FOR。Flask 的 request 对象只是从这里读取并封装了一层。
用 WSGI 中间件拦截并重写请求头的正确姿势
必须在 Flask 应用被调用前,修改传入的 environ 字典。常见错误是试图在 before_request 钩子里操作,那已经太晚了 —— 请求头早已解析完毕。
- 新建一个类,实现
__call__方法,接收environ和start_response - 在
environ中按HTTP_*键名修改(注意:原始 header 名会被转成大写、中划线变下划线、加HTTP_前缀) - 例如想把
User-Agent改成MyBot/1.0,就设environ['HTTP_USER_AGENT'] = 'MyBot/1.0' - 别忘了最后调用
self.app(environ, start_response)把控制权交还给 Flask
class HeaderRewriteMiddleware:
def __init__(self, app):
self.app = app
<pre class="brush:php;toolbar:false;">def __call__(self, environ, start_response):
# 强制覆盖 User-Agent
environ['HTTP_USER_AGENT'] = 'MyBot/1.0'
# 添加 X-Forwarded-Proto(若未设置)
if 'HTTP_X_FORWARDED_PROTO' not in environ:
environ['HTTP_X_FORWARDED_PROTO'] = 'https'
return self.app(environ, start_response)使用方式
app = Flask(name) app.wsgi_app = HeaderRewriteMiddleware(app.wsgi_app)
重写 X-Real-IP 或 X-Forwarded-For 的风险点
这类头通常由反向代理(Nginx、Cloudflare)注入,用于传递真实客户端 IP。手动重写极易引发安全问题或日志错乱。
- 如果上游已设
X-Forwarded-For,你再覆盖,Flask 的request.remote_addr可能变成伪造值 - 某些部署环境(如 Gunicorn + Nginx)依赖这些头做 IP 白名单,改错会导致 403
- 想“修复” IP 获取逻辑,更稳妥的方式是配置
app.config['TRUSTED_PROXIES']并用request.access_route
为什么不用 app.before_request + g 模拟?
可以存到 g 里供视图用,但这只是“模拟重写”,所有基于 request.headers 的第三方扩展(比如 Flask-Login 的 user-agent 检查、某些鉴权中间件)仍然看到原始头。真正的全局生效,绕不开 WSGI 层。
实际部署时最容易被忽略的是:WSGI 中间件对 environ 的修改,不会反映在 request.headers 的 dict() 输出里 —— 因为 Flask 初始化 Headers 后就不会再同步 environ 变更。调试时别只打印 dict(request.headers),要直接看 environ 字典。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











