Uvicorn不直接设置响应头,仅转发应用通过http.response.start消息传入的bytes类型headers;FastAPI中应显式返回Response或JSONResponse并传入字符串headers字典,手写ASGI时须确保headers为[[b'k',b'v']]格式。

Uvicorn 本身不直接处理响应头设置,它是 ASGI 服务器,只负责把请求转给应用、把应用返回的 send 消息按协议发出去;真正控制响应头的地方,是你的 ASGI 应用逻辑(比如 FastAPI、Starlette,或手写 ASGI callable)。
FastAPI 中设置自定义响应头最常用的方式
FastAPI 提供了 Response 类和 Header 依赖两种主流方式,推荐优先用 Response —— 它明确、可控、不隐式。
常见错误是试图在函数体里直接修改 response.headers 却没声明返回类型,导致 FastAPI 自动包装成 JSONResponse 并覆盖你设的头。
- 必须显式声明返回类型为
Response或其子类(如JSONResponse),否则 FastAPI 会按返回值自动推断,大概率丢掉你手动加的头 -
JSONResponse构造时可直接传headers字典,键名用字符串,值也必须是字符串(非字节) - 若需动态计算 header 值(比如基于请求参数生成 ETag),用
Response更灵活
from fastapi import FastAPI, Response
from starlette.responses import JSONResponse
app = FastAPI()
@app.get("/with-headers")
def with_headers():
return JSONResponse(
content={"status": "ok"},
headers={
"X-Processed-Time": "123ms",
"Cache-Control": "no-cache",
"X-Content-Type-Options": "nosniff"
}
)
@app.get("/dynamic-headers")
def dynamic_headers():
response = Response(content='{"msg":"done"}', media_type="application/json")
response.headers["X-Timestamp"] = "2026-10-14T22:19:00Z"
return response
手写 ASGI callable 时如何发带自定义头的响应
如果你绕过 FastAPI,直接写 ASGI 应用(比如做轻量 Thumbnail Server),响应头必须通过 http.response.start 消息的 headers 字段传入,且所有 header key/value 都必须是 bytes,不是字符串。
Uvicorn 0.52.1 是 Python ASGI Web 服务器,提供异步应用服务及 WebSocket 支持,常用于 FastAPI、Starlette 等应用的开发和部署。本下载为官方 PyPI 通用 wheel 包,可使用 pip 安装,并由包管理器处理所需依赖。
容易踩的坑:用字符串当 header 值会触发 TypeError: expected bytes;漏掉 b'content-type' 可能导致浏览器解析失败;Cache-Control 值写错格式(比如混入空格或非法字符)会被忽略。
-
headers是二维字节列表:[[b'key1', b'value1'], [b'key2', b'value2']] - 务必确保每个 value 是合法 ASCII 字节串;中文或特殊符号需编码(如
b"utf-8") - 不要在
http.response.body消息里重复塞 header,那会被忽略
async def app(scope, receive, send):
if scope['type'] == 'http':
await send({
'type': 'http.response.start',
'status': 200,
'headers': [
[b'content-type', b'application/json'],
[b'x-server', b'uvicorn-custom'],
[b'cache-control', b'max-age=300']
]
})
await send({
'type': 'http.response.body',
'body': b'{"ok": true}'
})
Uvicorn 启动参数对响应头的影响
Uvicorn 自身不注入或改写响应头,但有两个启动选项间接影响 header 行为:
-
--proxy-headers:启用后,Uvicorn 会从X-Forwarded-*头中提取信息,并重写scope中的scheme、host等字段;这会影响后续应用生成的Location或Link头的值,但不会自动加新 header -
--forwarded-allow-ips:配合--proxy-headers使用,指定可信代理 IP;若配错,可能导致X-Forwarded-Proto被忽略,使应用误判 HTTPS 状态,进而生成错误的Strict-Transport-Security或重定向头
这两个参数不改变你代码里写的响应头,但会改变应用运行时看到的请求上下文,从而影响你代码中基于请求生成响应头的逻辑。
最易被忽略的一点:ASGI 规范要求所有 header 值必须是 bytes,而 FastAPI 的 JSONResponse 等封装层做了字符串到字节的转换;一旦你脱离这些封装(比如用 StreamingResponse 或自定义 Response 子类),就必须自己确保 headers 字典里的 value 是字节串,否则 Uvicorn 在序列化时会直接报错退出。

















