FastAPI返回PDF文件,OpenAPI生成的Python客户端报UnicodeDecodeError
问题:OpenAPI Generator Python客户端解码PDF二进制数据触发UnicodeDecodeError
我正在构建一个系统,其中FastAPI服务端接口以二进制数据形式返回PDF文件,使用OpenAPI Generator Python(7.6.0、7.9.0版本)生成客户端。但调用该接口时,客户端会尝试将二进制PDF数据解码为UTF-8文本,导致出现UnicodeDecodeError。
已尝试的解决方案(均无效)
- 尝试传入
_preload_content=False以阻止客户端自动解码响应,但生成的客户端方法不接受该参数,引发Pydantic验证错误; - 使用
StreamingResponse返回响应,问题依旧; - 通过API文档UI或curl测试接口,可正常接收PDF文件。
服务端代码(FastAPI 接口)
from fastapi import APIRouter, HTTPException, BackgroundTasks from fastapi.responses import FileResponse, StreamingResponse import os router = APIRouter() @router.get( "/purchases/{order_id}/shipment_page", responses={ 200: { "description": "PDF file response", "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } } } ) async def get_shipment_page_route(order_id: str, background_tasks: BackgroundTasks): temp_file_path = f"temp_purchase_{order_id}.pdf" try: # 获取PDF内容(二进制数据) pdf_content = get_shipment_page(order_id) # 返回bytes类型 # 将PDF内容写入临时文件 with open(temp_file_path, "wb") as temp_file: temp_file.write(pdf_content) headers = { "Content-Disposition": f"attachment; filename=Purchase_{order_id}.pdf", } # 响应发送后删除临时文件 background_tasks.add_task(remove_file, temp_file_path) # 返回PDF文件 return FileResponse( path=temp_file_path, filename=f"Purchase_{order_id}.pdf", media_type="application/pdf", headers=headers ) except Exception as e: if os.path.exists(temp_file_path): os.remove(temp_file_path) raise HTTPException(status_code=500, detail=str(e)) def remove_file(path: str): if os.path.exists(path): os.remove(path)
客户端代码(OpenAPI生成的客户端)
import retumilo_client from retumilo_client.rest import ApiException import frappe import logging configuration = retumilo_client.Configuration(...) def get_purchase_order_shipment_page(order_id: str): with retumilo_client.ApiClient(configuration) as api_client: # 创建API实例 api_instance = retumilo_client.DefaultApi(api_client) try: # 获取PDF内容 pdf_content = api_instance.get_shipment_page_route_purchases_order_id_shipment_page_get(order_id) return pdf_content except ApiException as e: logger.error(f"调用DefaultApi时异常: {e}") raise ValueError("获取发货页面失败") except Exception as e: logger.error(f"意外错误: {e}") raise ValueError("发生意外错误")
错误栈(Traceback)
22:26:38 web.1 | Traceback (most recent call last): 22:26:38 web.1 | File "apps/xxxx_integration/xxxx_integration/xxxx_integration/integration/purchase_order.py", line 81, in get_purchase_order_shipment_page 22:26:38 web.1 | pdf_content = api_instance.get_shipment_page_route_purchases_order_id_shipment_page_get(order_id) 22:26:38 web.1 | File "env/lib/python3.10/site-packages/pydantic/validate_call_decorator.py", line 59, in wrapper_function 22:26:38 web.1 | return validate_call_wrapper(*args, **kwargs) 22:26:38 web.1 | File "env/lib/python3.10/site-packages/pydantic/_internal/_validate_call.py", line 81, in __call__ 22:26:38 web.1 | res = self.__pydantic_validator__.validate_python(pydantic_core.ArgsKwargs(args, kwargs)) 22:26:38 web.1 | File "env/lib/python3.10/site-packages/retumilo_client/api/default_api.py", line 1157, in get_shipment_page_route_purchases_order_id_shipment_page_get 22:26:38 web.1 | return self.api_client.response_deserialize( 22:26:38 web.1 | File "env/lib/python3.10/site-packages/retumilo_client/api_client.py", line 318, in response_deserialize 22:26:38 web.1 | response_text = response_data.data.decode(encoding) 22:26:38 web.1 | UnicodeDecodeError: 'utf-8' codec can't decode byte 0x9c in position 197: invalid start byte
内容的提问来源于stack exchange,提问作者Starid
相关产品推荐
相关产品推荐

