Skip to content

Commit a354532

Browse files
committed
add post fastapi-cookie-headers
1 parent 469be87 commit a354532

File tree

15 files changed

+1477
-28
lines changed

15 files changed

+1477
-28
lines changed
Lines changed: 216 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,216 @@
1+
+++
2+
date = '2025-08-11T10:00:00+08:00'
3+
draft = false
4+
title = 'Fastapi Cookie and Header Parameters'
5+
+++
6+
这篇文章介绍 Fastapi 的 Cookie 和 Header 参数
7+
8+
### Cookie Parameters
9+
通过定义 `Query``Path` 参数一样定义 `Cookie` 参数
10+
```Python
11+
from typing Annotated
12+
from fastapi import Cookie, FastAPI
13+
14+
app = FastAPI()
15+
16+
@app.get("/items/")
17+
async def read_items(ads_id: Annotated[str | None, Cookie()] = None):
18+
return {"ads_id": ads_id}
19+
```
20+
21+
#### Cookie Parameters Models
22+
如果有一组相关的 cookies, 可以使用 Pydantic model 来声明.
23+
24+
这样可以在多个部分复用这个模型, 同时还能一次性为所有参数声明验证规则和元数据.
25+
26+
下面使用 Pydantic 模型定义 Cookies, 然后将参数声明为 `Cookie`
27+
```Python
28+
from typing import Annotated
29+
from fastapi import FastAPI, Cookie
30+
from pydantic import BaseModel
31+
32+
app = FastAPI()
33+
34+
class Cookie(BaseModel):
35+
session_id: str
36+
fatebook_tracker: str | None = None
37+
googall_tracker: str | None = None
38+
39+
@app.get("/items/")
40+
async def read_items(cookies: Annotated[Cookies, Cookie()]):
41+
return cookies
42+
```
43+
44+
#### Forbid Extra Cookies 禁止额外的Cookie
45+
在某些场景下(虽然并不常见), 可能希望限制 API 只能接收特定的 Cookie.
46+
这样, API 就可以"自己"管理 Cookie 同意策略了.
47+
```Python
48+
from typing import Annotated
49+
from fastapi import FastAPI, Cookie
50+
from pydantic import BaseModel
51+
52+
app = FastAPI()
53+
54+
class Cookies(BaseModel):
55+
model_config = {"extra": "forbid"} # forbid extra cookies
56+
57+
session_id: str
58+
fatebook_tracker: str | None = None
59+
googall_tracker: str | None = None
60+
61+
@app.get("/items/")
62+
async def read_items(cookies: Annotated[Cookies, Cookie()]):
63+
return cookies
64+
```
65+
这样, 如果客户端发送额外的 cookies, 则会收到一个错误响应. 例如, 客户端发送了 `santa_tracker` 这个额外 Cookie
66+
```Python
67+
santa_tracker = good-list-please
68+
```
69+
将会收到如下错误响应
70+
```JSON
71+
{
72+
"detail": [
73+
{
74+
"type": "extra_forbidden",
75+
"loc": ["cookie", "santa_tracker"],
76+
"msg": "Extra inputs are not permitted",
77+
"input": "good-list-please",
78+
}
79+
]
80+
}
81+
```
82+
83+
84+
85+
86+
### Header Parameters
87+
同样的, 通过定义 `Query``Path` 参数一样定义 `Header` 参数
88+
```Python
89+
from typing import Annotated
90+
from fastapi import FastAPI, Header
91+
92+
app = FastAPI()
93+
94+
@app.get("/items/")
95+
async def read_items(user_agent: Annotated[str | None, Header()] = None):
96+
return {"User-Agent": user_agent}
97+
```
98+
99+
100+
#### Automatic conversoin 自动转换
101+
`Header` 拥有一些在 `Path`, `Query``Cookie` 上的额外功能
102+
103+
大多数标准的 header 都通过一个连字符(hyphen character), 也称为减号(minus symbol)分开,
104+
但是变量 `user-agent` 这样在 Python 中是不合法的. 所以, 默认情况下 `Header` 会将参数名中的 hypen(-) 使用下划线 undersocre(\_) 替换.
105+
106+
同样的, HTTP headers 是不区分大小写的, 所以可以使用标准的 Python 风格 (snake\_case). 因此可以使用 `user_agent` 在 Python 代码中, 而不需要首字母大写成 `User_Agent`.
107+
108+
如果想要禁止这种自动转换, 需要将 `Header` 的参数 `convert_undersocres` 设置为 `False`
109+
110+
```Python
111+
from typing import Typing
112+
from fastapi import FastAPI, Header
113+
114+
app = FastAPI()
115+
116+
@app.get("/items/")
117+
async def read_items(
118+
strange_header: Annotated[str | None, Header(convert_undersocres=False)] = None
119+
):
120+
return {"strange_header": strange_header}
121+
```
122+
123+
#### Duplicate headers 重复请求头
124+
一个请求中可能会收到重复的 headers, 也就是同一个 header 有多个值.
125+
126+
可以在类型声明中使用 `list` 来处理这种情况, 这样会得到一个 Python 列表.
127+
128+
例如要声明一个可能多次出现的 `X-Token` 头部, 可以这样写:
129+
```Python
130+
from typing import Annotated
131+
from fastapi import FastAPI, Header
132+
133+
app = FastAPI()
134+
135+
@app.get("/items/")
136+
async def read_items(x_token: Annotated[list[str] | None, Header()] = None):
137+
return {"X-Token values": x_token}
138+
```
139+
140+
如果向该接口发送两个这样的 HTTP headers
141+
```
142+
X-Token: foo
143+
X-Token: bar
144+
```
145+
146+
返回类似这样
147+
```Python
148+
{
149+
"X-Token values": [
150+
"bar",
151+
"foo"
152+
]
153+
}
154+
```
155+
156+
157+
#### Header parameters models 请求头参数模型
158+
同样可以使用 Pydantic model 定义 Header Parameters, 这样可以在多个地方复用模型, 还能一次性为所有参数声明规则和元数据
159+
```Python
160+
from typing import Annotated
161+
from fastapi import FastAPI, Header
162+
from pydantic import BaseModel
163+
164+
app = FastAPI()
165+
166+
class CommonHeaders(BaseModel):
167+
host: str
168+
save_data: str
169+
if_modified_since: str | None = None
170+
traceparent: str | None = None
171+
x_tag: list[str] = []
172+
173+
@app.get("/items")
174+
async def read_items(headers: Annotated[CommonHeaders, Header()]):
175+
return headers
176+
```
177+
178+
#### Forbid extra headers 禁止额外请求头
179+
同样也可以禁止额外的 headers
180+
```Python
181+
class CommonHeaders(BaseModel):
182+
model_config = {"extra": "forbid"} # 禁止额外字段
183+
...
184+
```
185+
186+
如果客户端尝试发送额外的 Header,将会收到错误响应. 例如, 客户端发送了 `tool` 这个额外 Header
187+
```
188+
tool: plumbus
189+
```
190+
191+
将会收到如下错误响应
192+
```json
193+
{
194+
"detail": [
195+
{
196+
"type": "extra_forbidden",
197+
"loc": ["header", "tool"],
198+
"msg": "Extra inputs are not permitted",
199+
"input": "plumbus"
200+
}
201+
]
202+
}
203+
```
204+
205+
#### Disable convert undersocres
206+
同样可以禁用自动下换线转换
207+
208+
与普通的 Header 参数一样, 如果参数名中包含下划线 undersocre (\_), FastAPI 会自动将其转换为连字符 hypens (-)
209+
```Python
210+
async def read_items(
211+
headers: Annotated[CommonHeaders, Header(convert_underscores=False)],
212+
):
213+
...
214+
```
215+
216+
> 在将 `convert_underscores` 设置为 False 前, 注意有些 HTTP 代理和服务器不允许带下划线的头部字段

content/posts/gitignore.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ bin
5151

5252
> 西西弗斯推着一块写着 `.DS_Store` 的巨石艰难上山
5353
54-
如何改变偷偷溜进来的文件循环呢? 去教育每一个提交合并请求的人肯定不行, 得通过自动化工具结局, 而不是主观沟通
54+
如何改变偷偷溜进来的文件循环呢? 去教育每一个提交合并请求的人肯定不行, 得通过自动化工具解决, 而不是主观沟通
5555

5656
幸运的是, 可以将这个黑名单变成白名单, 可以通过默认忽略所有文件, 然后只手动“取消忽略”明确允许的文件
5757
```

content/posts/python-asyncio.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,3 +56,7 @@ loop.close() # 8
5656
7. 再次运行事件循环, 直到所有 pending 任务完成(确保程序退出前 loop 是干净的)
5757

5858
8. 关闭事件循环
59+
60+
61+
Python 中的 Asyncio 暴露了关于事件循环的大量底层机制, 并要求了解生命周期管理等方面.
62+
不同于 Node.js, 例如他还包含了一个事件循环, 但在某种程度上将其隐藏起来了.

public/archives/index.html

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,10 +51,13 @@
5151
<span class="max-w-[4rem] md:max-w-none truncate">Home</span></a></li><li class="flex items-center gap-1 md:gap-2 min-w-0"><span class="text-muted-foreground/50 flex-shrink-0"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 5l7 7-7 7"/></svg>
5252
</span><span class="text-foreground flex items-center gap-0.5 md:gap-1 font-medium min-w-0 flex-shrink-0"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/></svg>
5353
<span class="max-w-[3rem] md:max-w-none truncate">Archives</span></span></li></ol></nav><header class=mb-8><div class="mb-4 flex items-center gap-3"><svg class="h-6 w-6" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 8h14M5 8a2 2 0 110-4h14a2 2 0 110 4M5 8v10a2 2 0 002 2h10a2 2 0 002-2V8m-9 4h4"/></svg><h1 class="text-foreground text-3xl font-bold">Archives</h1></div><p class="text-muted-foreground mb-6">Browse all articles in chronological order and discover what interests you.</p><div class="text-muted-foreground flex items-center gap-4 text-sm"><div class="flex items-center gap-1"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"/></svg>
54-
<span>8 posts total</span></div><div class="flex items-center gap-1"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
55-
<span>Timeline view</span></div></div></header><div class=relative><div class="bg-border absolute top-0 bottom-0 left-4 w-0.5"></div><div class=mb-12><div class="relative mb-8 flex items-center"><div class="bg-primary absolute left-0 z-10 flex h-8 w-8 items-center justify-center rounded-full"><svg class="h-4 w-4 text-primary-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg></div><div class=ml-12><h2 class="text-foreground text-2xl font-bold">2025</h2><p class="text-muted-foreground text-sm">8
56-
posts</p></div></div><div class="relative mb-8"><div class="relative mb-4 flex items-center"><div class="bg-accent border-background absolute left-2 z-10 h-4 w-4 rounded-full border-2"></div><div class=ml-12><h3 class="text-foreground text-lg font-semibold">August 2025</h3><p class="text-muted-foreground text-xs">8
57-
posts</p></div></div><div class="ml-12 space-y-3"><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/fastapi-body-advanced-uses/ class=block>FastAPI Body Advanced Uses</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
54+
<span>9 posts total</span></div><div class="flex items-center gap-1"><svg class="h-4 w-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
55+
<span>Timeline view</span></div></div></header><div class=relative><div class="bg-border absolute top-0 bottom-0 left-4 w-0.5"></div><div class=mb-12><div class="relative mb-8 flex items-center"><div class="bg-primary absolute left-0 z-10 flex h-8 w-8 items-center justify-center rounded-full"><svg class="h-4 w-4 text-primary-foreground" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg></div><div class=ml-12><h2 class="text-foreground text-2xl font-bold">2025</h2><p class="text-muted-foreground text-sm">9
56+
posts</p></div></div><div class="relative mb-8"><div class="relative mb-4 flex items-center"><div class="bg-accent border-background absolute left-2 z-10 h-4 w-4 rounded-full border-2"></div><div class=ml-12><h3 class="text-foreground text-lg font-semibold">August 2025</h3><p class="text-muted-foreground text-xs">9
57+
posts</p></div></div><div class="ml-12 space-y-3"><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/fastapi-cookie-and-header-parameters/ class=block>Fastapi Cookie and Header Parameters</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
58+
<time datetime=2025-08-11>08-11</time></div><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3A9 9 0 113 12a9 9 0 0118 0z"/></svg>
59+
<span>3
60+
min</span></div></div></div></div></article><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/fastapi-body-advanced-uses/ class=block>FastAPI Body Advanced Uses</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>
5861
<time datetime=2025-08-09>08-09</time></div><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3A9 9 0 113 12a9 9 0 0118 0z"/></svg>
5962
<span>5
6063
min</span></div></div></div></div></article><article class="group bg-card border-border hover:bg-accent/50 rounded-lg border p-4 transition-all duration-300"><div class="flex items-center justify-between gap-4"><div class="min-w-0 flex-1"><h4 class="text-foreground group-hover:text-primary mb-3 font-medium transition-colors duration-200"><a href=/posts/git-whitelist/ class=block>Git Whitelist</a></h4><div class="text-muted-foreground flex items-center gap-4 text-xs"><div class="flex items-center gap-1"><svg class="h-3 w-3" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5A2 2 0 003 7v12a2 2 0 002 2z"/></svg>

0 commit comments

Comments
 (0)