You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

FastAPI对接Next.js请求端点报500及序列化错误排查

FastAPI 对接 Next.js 数据请求异常排查

相关代码

后端FastAPI路由原始代码

@router.get('/public',response_class=HTMLResponse)
def job_list_view(request:Request):
    async def get_todos() -> dict:
        todos = [
        {
            "id": "1",
            "item": "Read a book."
        },
        {
            "id": "2",
            "item": "Cycle around town."
        }
            ]
        return { "data": todos }

前端Next.js请求原始代码

export async function getServerSideProps() {
  const jobs = await fetch('http://localhost:8000/public/')
  console.log(jobs)
  const res = jobs.json()
  return {
    props: { jobs: res },
  }
}

异常表现

  • Postman直接访问接口返回Internal Server Error
  • 前端抛出两类报错:
    1. FetchError:http://localhost:8000/public/响应体为无效JSON,位置0处存在意外token I
    2. 序列化错误:getServerSideProps在/路由返回的.jobs为[object Promise]对象,无法序列化为JSON,仅支持返回可JSON序列化的数据类型

前端报错详情

error - unhandledRejection: FetchError: invalid json response body at http://localhost:8000/public/ reason: Unexpected token I in JSON at position 0
error - Error: Error serializing `.jobs` returned from `getServerSideProps` in "/".
Reason: `object` ("[object Promise]") cannot be serialized as JSON. Please only return JSON serializable data types.

后端报错详情

FastAPI控制台抛出AttributeError,核心错误为'dict' object has no attribute 'encode',完整堆栈如下:

INFO:     127.0.0.1:63133 - "GET /public/ HTTP/1.1" 500 Internal Server Error
ERROR:    Exception in ASGI application
Traceback (most recent call last):
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 366, in run_asgi       
    result = await app(self.scope, self.receive, self.send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\uvicorn\middleware\proxy_headers.py", line 75, in __call__       
    return await self.app(scope, receive, send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\fastapi\applications.py", line 269, in __call__
    await super().__call__(scope, receive, send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\applications.py", line 124, in __call__
    await self.middleware_stack(scope, receive, send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\middleware\errors.py", line 184, in __call__
    raise exc
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\middleware\errors.py", line 162, in __call__
    await self.app(scope, receive, _send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\middleware\cors.py", line 84, in __call__
    await self.app(scope, receive, send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\middleware\authentication.py", line 48, in __call__    
    await self.app(scope, receive, send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\exceptions.py", line 93, in __call__
    raise exc
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\exceptions.py", line 82, in __call__
    await self.app(scope, receive, sender)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 21, in __call__      
    raise e
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\fastapi\middleware\asyncexitstack.py", line 18, in __call__      
    await self.app(scope, receive, send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\routing.py", line 670, in __call__
    await route.handle(scope, receive, send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\routing.py", line 266, in handle
    await self.app(scope, receive, send)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\routing.py", line 65, in app
    response = await func(request)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\fastapi\routing.py", line 251, in app
    response = actual_response_class(response_data, **response_args)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\responses.py", line 49, in __init__
    self.body = self.render(content)
  File "D:\TEMP\job_search - SQL\venv\lib\site-packages\starlette\responses.py", line 57, in render
    return content.encode(self.charset)
AttributeError: 'dict' object has no attribute 'encode'

根因分析

  1. 后端响应类型配置错误:接口指定response_class=HTMLResponse,该响应类会尝试对返回内容调用字符串的.encode()方法编码,但路由实际返回的是dict对象,没有encode方法,直接触发500错误。FastAPI默认返回HTML格式的500错误页,页面开头为Internal Server Error,首字符为I,这就是前端解析JSON时提示Unexpected token I的来源。
  2. 后端逻辑冗余无效:路由方法内部定义了异步函数get_todos()但从未调用,即使修复响应类型问题,也无法返回预期的待办事项数据。
  3. 前端Promise未等待:Response.json()是异步方法,返回Promise对象,原始代码没有加await等待解析完成,直接把Promise对象传给props,触发序列化错误。

修复方案

后端修复

  • 接口返回JSON数据时无需指定HTMLResponse,FastAPI默认会自动将dict、列表等数据结构序列化为JSON格式返回,也可显式指定response_class=JSONResponse
  • 移除路由内部未调用的嵌套异步函数,直接在路由方法内实现数据返回逻辑
    修复后代码:
from fastapi import APIRouter, Request

router = APIRouter()

@router.get('/public')
async def job_list_view(request: Request):
    todos = [
        {"id": "1", "item": "Read a book."},
        {"id": "2", "item": "Cycle around town."}
    ]
    return {"data": todos}

前端修复

  • 调用res.json()时添加await关键字,等待JSON解析完成后再赋值给变量
    修复后代码:
export async function getServerSideProps() {
  const res = await fetch('http://localhost:8000/public/')
  const jobs = await res.json()
  return {
    props: { jobs },
  }
}

内容的提问来源于stack exchange,提问作者Julie An

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 09:36:37