階:在 JSON 中用 Base64 傳輸二進(jìn)制數(shù)據(jù)(bytes 字段實(shí)戰(zhàn)))
FastAPI 進(jìn)階在 JSON 中用 Base64 傳輸二進(jìn)制數(shù)據(jù)bytes 字段實(shí)戰(zhàn)【免費(fèi)下載鏈接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production項(xiàng)目地址: https://gitcode.com/GitHub_Trending/fa/fastapi本篇指南講解 FastAPI 中一個(gè)進(jìn)階但非常實(shí)用的場(chǎng)景當(dāng)你的接口必須接收和發(fā)送 JSON 數(shù)據(jù)、其中又需要攜帶二進(jìn)制內(nèi)容bytes時(shí)如何利用 Pydantic 的val_json_bytes與ser_json_bytes配置把二進(jìn)制數(shù)據(jù)安全地以 base64 編碼嵌入 JSON 請(qǐng)求體與響應(yīng)體。讀完本文你將掌握 base64 方案與文件上傳/下載方案的取舍原則、bytes字段模型配置的完整寫(xiě)法以及 FastAPI 源碼中 OpenAPI Schema 是如何自動(dòng)生成contentEncoding: base64聲明的底層機(jī)制。何時(shí)需要用 Base64 而不是文件如果你的應(yīng)用需要接收和發(fā)送 JSON 數(shù)據(jù)但其中必須包含二進(jìn)制數(shù)據(jù)就可以把這些二進(jìn)制數(shù)據(jù)編碼為 base64 字符串來(lái)傳輸。在選擇方案之前先評(píng)估是否可以直接使用 請(qǐng)求文件 來(lái)上傳二進(jìn)制數(shù)據(jù)、使用 自定義響應(yīng) – FileResponse 來(lái)下發(fā)二進(jìn)制數(shù)據(jù)而不是把二進(jìn)制內(nèi)容編碼進(jìn) JSON。兩者的取舍依據(jù)如下JSON 只能包含 UTF-8 編碼的字符串因此它無(wú)法承載原始字節(jié)raw bytesBase64 可以把二進(jìn)制數(shù)據(jù)編碼成字符串但代價(jià)是需要比原始二進(jìn)制數(shù)據(jù)更多的字符通常膨脹約 1/3因此在傳輸效率上一般不如直接傳文件只有當(dāng)你確實(shí)必須把二進(jìn)制數(shù)據(jù)內(nèi)嵌在 JSON 中、且無(wú)法改用文件方案時(shí)才使用 base64。用 Pydanticbytes字段接收輸入數(shù)據(jù)聲明一個(gè)帶bytes字段的 Pydantic 模型并在模型配置中設(shè)置val_json_bytes即可告訴 Pydantic在校驗(yàn)validate輸入的 JSON 數(shù)據(jù)時(shí)使用 base64。校驗(yàn)過(guò)程中base64 字符串會(huì)被自動(dòng)解碼為字節(jié)對(duì)象。完整示例見(jiàn) docs_src/json_base64_bytes/tutorial001_py310.py其中接收端模型為from fastapi import FastAPI from pydantic import BaseModel class DataInput(BaseModel): description: str data: bytes model_config {val_json_bytes: base64} app FastAPI() app.post(/data) def post_data(body: DataInput): content body.data.decode(utf-8) return {description: body.description, content: content}啟動(dòng)應(yīng)用后訪(fǎng)問(wèn)/docsSwagger UI 會(huì)展示字段data期望接收 base64 編碼的字節(jié)此時(shí)可以發(fā)送如下請(qǐng)求{ description: Some data, data: aGVsbG8 }提示aGVsbG8就是字符串hello的 base64 編碼。Pydantic 會(huì)解碼這個(gè) base64 字符串并在模型的data字段中把原始字節(jié)交給你。隨后你會(huì)收到類(lèi)似這樣的響應(yīng){ description: Some data, content: hello }這里的關(guān)鍵點(diǎn)在于端點(diǎn)函數(shù)拿到的body.data已經(jīng)是解碼后的bytes類(lèi)型示例中再用.decode(utf-8)轉(zhuǎn)回字符串base64 編解碼完全由 Pydantic 在模型邊界處自動(dòng)完成業(yè)務(wù)代碼無(wú)需手動(dòng)調(diào)用任何base64模塊。用 Pydanticbytes字段輸出數(shù)據(jù)對(duì)于輸出數(shù)據(jù)可以在模型配置中使用ser_json_bytes。Pydantic 在生成 JSON 響應(yīng)時(shí)會(huì)把字節(jié)序列化serialize為 base64 字符串class DataOutput(BaseModel): description: str data: bytes model_config {ser_json_bytes: base64} app.get(/data) def get_data() - DataOutput: data hello.encode(utf-8) return DataOutput(descriptionA plumbus, datadata)響應(yīng)體中data字段就會(huì)以aGVsbG8這樣的 base64 字符串形式返回。倉(cāng)庫(kù)中的測(cè)試 tests/test_tutorial/test_json_base64_bytes/test_tutorial001.py 正是如此斷言的def test_get_data(client: TestClient): response client.get(/data) assert response.status_code 200, response.text assert response.json() {description: A plumbus, data: aGVsbG8}測(cè)試同時(shí)覆蓋了輸入方向發(fā)送SGVsbG8sIFdvcmxkIQ解碼為Hello, World!驗(yàn)證了這套機(jī)制在真實(shí)請(qǐng)求/響應(yīng)鏈路中的端到端行為。同一模型同時(shí)處理輸入和輸出當(dāng)然你也可以配置同一個(gè)模型讓 base64 同時(shí)用于輸入校驗(yàn)和輸出序列化class DataInputOutput(BaseModel): description: str data: bytes model_config { val_json_bytes: base64, ser_json_bytes: base64, } app.post(/data-in-out) def post_data_in_out(body: DataInputOutput) - DataInputOutput: return body此時(shí)請(qǐng)求體里的 base64 字符串會(huì)被解碼成bytes傳入端點(diǎn)端點(diǎn)把同一個(gè)模型對(duì)象返回后bytes又會(huì)以 base64 形式序列化進(jìn)響應(yīng)。上述測(cè)試文件中的test_post_data_in_out驗(yàn)證了這一回環(huán)發(fā)送SGVsbG8sIFdvcmxkIQ響應(yīng)體中data原樣返回同一 base64 字符串。源碼視角OpenAPI Schema 是怎么知道要聲明 base64 的一個(gè)值得注意的細(xì)節(jié)是配置val_json_bytes/ser_json_bytes后OpenAPI 文檔會(huì)自動(dòng)為bytes字段生成contentEncoding: base64和contentMediaType: application/octet-stream聲明/docs界面因此能正確提示該字段期望 base64 字符串。從上面的測(cè)試快照test_openapi_schema可以看到生成的 Schema 片段data: { type: string, contentEncoding: base64, contentMediaType: application/octet-stream, title: Data }這一行為來(lái)自 FastAPI 對(duì) Pydantic JSON Schema 生成器的定制覆蓋位于 fastapi/_compat/v2.pyclass GenerateJsonSchema(_GenerateJsonSchema): def bytes_schema(self, schema: CoreSchema) - JsonSchemaValue: json_schema {type: string, contentMediaType: application/octet-stream} bytes_mode ( self._config.ser_json_bytes if self.mode serialization else self._config.val_json_bytes ) if bytes_mode base64: json_schema[contentEncoding] base64 self.update_with_validations(json_schema, schema, self.ValidationsMapping.bytes) return json_schema從這段源碼可以看出兩個(gè)要點(diǎn)FastAPI 重寫(xiě)了 Pydantic 的bytes_schema方法先按bytes的默認(rèn)語(yǔ)義生成type: stringcontentMediaType: application/octet-stream然后根據(jù)當(dāng)前模式校驗(yàn)?zāi)J阶xval_json_bytes、序列化模式讀ser_json_bytes當(dāng)配置值為base64時(shí)追加contentEncoding: base64聲明。也就是說(shuō)Schema 聲明與實(shí)際的數(shù)據(jù)編解碼行為是同一份模型配置驅(qū)動(dòng)的兩面同一組model_config既決定運(yùn)行時(shí)如何解碼/編碼字節(jié)也決定 OpenAPI 文檔如何向調(diào)用方描述字段格式。小結(jié)與適用邊界優(yōu)先用文件上傳二進(jìn)制用請(qǐng)求文件、下發(fā)二進(jìn)制用FileResponseJSON 無(wú)法承載原始字節(jié)base64 是可嵌入 JSON 的通用編碼但字符膨脹使其通常不如直接傳文件高效輸入方向用model_config {val_json_bytes: base64}輸出方向用{ser_json_bytes: base64}兩者可同時(shí)配置在同一個(gè)模型上配置生效后/docs中的 OpenAPI Schema 會(huì)自動(dòng)帶上contentEncoding: base64聲明調(diào)用方包括自動(dòng)生成的客戶(hù)端能據(jù)此正確編碼請(qǐng)求體參考實(shí)現(xiàn)示例應(yīng)用、端到端測(cè)試、Schema 生成定制?!久赓M(fèi)下載鏈接】fastapiFastAPI framework, high performance, easy to learn, fast to code, ready for production項(xiàng)目地址: https://gitcode.com/GitHub_Trending/fa/fastapi創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考