如何在FastAPI中正确返回JSON格式数据?解决与Flask格式差异
FastAPI与Flask返回JSON格式差异问题解决
问题根源
Flask和FastAPI的响应处理机制存在本质差异:
- Flask会自动识别返回的
dict/list,调用jsonify将其序列化为标准JSON响应;即便返回的是json.dumps生成的字符串,Flask也会将其识别为JSON内容直接返回。 - FastAPI基于Pydantic/Starlette实现,若返回的是Python原生数据结构(
dict/list),会自动用内置编码器完成序列化;但如果返回的是字符串,会直接将其作为纯文本返回,导致字符串被二次转义(出现嵌套引号、转义符)。
你的代码中手动调用json.dumps()返回JSON字符串而非原生数据结构,这就是FastAPI返回格式异常的核心原因。
解决方案
方案1:返回原生数据结构,自定义JSON编码器处理日期类型
去掉json.dumps()调用,直接返回list/dict,同时给FastAPI配置自定义编码器处理date类型:
from fastapi import Request, APIRouter from fastapi.encoders import jsonable_encoder from datetime import date from google.cloud import bigquery router = APIRouter() bigquery_client = bigquery.Client() @router.get('/report') async def report(request: Request): source_id = request.query_params.get("source_id") # 补充source_id获取逻辑 response = get_user(bigquery_client, source_id) # 用自定义编码器处理日期类型,让FastAPI自动完成序列化 return jsonable_encoder(response, custom_encoder={date: lambda v: v.isoformat()}) def get_user(client, source_id): try: query = """ SELECT * FROM .....""" job_config = bigquery.QueryJobConfig( query_parameters=[ bigquery.ScalarQueryParameter("source_id", "STRING", source_id), ] ) query_job = client.query(query, job_config=job_config) result = [] for row in query_job: result.append(dict(row)) # 直接返回Python列表,而非JSON字符串 return result except Exception as e: return str(e)
方案2:转换Row为Dict时直接处理日期字段
如果不想配置全局编码器,可以在将BigQuery返回的Row转为字典时,主动把date类型转成字符串:
from datetime import date from google.cloud import bigquery from fastapi import Request, APIRouter router = APIRouter() bigquery_client = bigquery.Client() @router.get('/report') async def report(request: Request): source_id = request.query_params.get("source_id") response = get_user(bigquery_client, source_id) return response def get_user(client, source_id): try: query = """ SELECT * FROM .....""" job_config = bigquery.QueryJobConfig( query_parameters=[ bigquery.ScalarQueryParameter("source_id", "STRING", source_id), ] ) query_job = client.query(query, job_config=job_config) result = [] for row in query_job: row_dict = dict(row) # 遍历字典,将日期类型转为ISO格式字符串 for key, value in row_dict.items(): if isinstance(value, date): row_dict[key] = value.isoformat() result.append(row_dict) return result except Exception as e: return str(e)
效果验证
修改后,FastAPI会返回和Flask完全一致的标准JSON结构,不再出现转义后的字符串格式。
内容的提问来源于stack exchange,提问作者Mohamed Haydar
相关产品推荐
相关产品推荐

