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

SvelteKit对接FastAPI时fetch GET/POST请求长期pending排查

根因分析

以下是匹配所有异常现象的高概率根因,按优先级从高到低排列:

  • Chromium内核私有网络访问(PNA)预检拦截:这是最贴合所有故障特征的根因。Chromium从98版本后逐步强制启用PNA安全策略,当页面通过fetch/XHR向比当前上下文私密性更高的网络地址(环回地址localhost属于最高优先级的私密地址段)发起跨域请求时,会先发送OPTIONS预检请求,要求服务端返回Access-Control-Allow-Private-Network: true响应头,未收到对应头时会将请求挂起等待,不会发送正式业务请求。
    完全匹配的现象点:
    • Firefox目前默认未强制开启PNA校验,因此请求可以正常执行
    • curl/Postman/浏览器地址栏直接导航不属于跨域脚本发起的请求范畴,不触发PNA检查,因此全部正常
    • 预检请求默认超时时间很长,超时后偶发的浏览器放行逻辑就会出现搁置半小时到1小时才成功的情况
  • CORS允许源配置与前端实际端口不匹配:SvelteKit开发服务默认端口为5173,预览服务默认端口为4173,你当前配置的允许源仅为http://localhost:3000,如果前端实际运行端口不符,Chromium会严格校验Origin头拦截请求;Firefox在本地localhost场景下对CORS校验有宽松策略,可能出现Firefox可通但Chromium拦截的情况。
  • 中间件顺序错误导致预检被拦截:FastAPI/Starlette的中间件遵循「后注册先执行」的逻辑,如果在CORS中间件注册之后又添加了自定义中间件、或者路由层拦截了OPTIONS方法请求,会导致CORS中间件无法正常处理预检,请求直接挂起。
  • 异步路由阻塞事件循环:如果你的FastAPI async路由中存在未做线程池隔离的同步阻塞操作(比如同步IO、time.sleep、同步数据库调用),会阻塞整个服务事件循环,导致请求排队等待。
排查与修复步骤

按顺序执行以下操作即可定位并解决问题:

  1. 快速验证PNA问题
    打开Chrome/Chromium,访问本地配置地址chrome://flags/#private-network-access-respect-preflight-results,将选项设置为Disabled,重启浏览器后再次测试请求。如果请求恢复正常,即可100%确认是PNA策略导致的问题。
    修复代码参考,注意中间件注册顺序:
    from starlette.middleware.base import BaseHTTPMiddleware
    
    # 新增PNA响应头中间件
    class PrivateNetworkAllowMiddleware(BaseHTTPMiddleware):
        async def dispatch(self, request, call_next):
            response = await call_next(request)
            response.headers["Access-Control-Allow-Private-Network"] = "true"
            return response
    
    app = FastAPI()
    # PNA中间件要先于CORS中间件注册
    app.add_middleware(PrivateNetworkAllowMiddleware)
    app.add_middleware(
        CORSMiddleware,
        # 不要靠记忆写端口,把前端实际运行的Origin加进去,建议把SvelteKit常用端口都配上
        allow_origins=["http://localhost:3000", "http://localhost:5173", "http://localhost:4173"],
        allow_credentials=True,
        allow_methods=["*"],
        allow_headers=["*"],
    )
    app.include_router(router)
    
  2. 校验实际请求Origin
    打开浏览器开发者工具-网络面板,找到pending状态的请求,查看请求头中的Origin字段完整值,把该值原封不动加入CORS的allow_origins配置中,不要自行臆测前端运行端口。
  3. 检查OPTIONS预检请求状态
    在网络面板中勾选显示OPTIONS类型请求,点击按钮后观察是否有OPTIONS请求发出:
    • 如果OPTIONS请求本身处于pending状态,检查本地安全软件、防火墙是否拦截了环回接口的OPTIONS方法请求
    • 如果OPTIONS请求返回响应,检查响应头是否包含完整的Access-Control-Allow-Origin、Access-Control-Allow-Private-Network字段,缺失则对应补全
  4. 排除事件循环阻塞问题
    在接口入口处添加打印日志,点击按钮时观察后端是否立刻打印日志:
    • 如果后端很久之后才收到请求日志,说明问题出在浏览器预检/网络层,回到前3步排查
    • 如果后端立刻收到日志但很久才返回响应,检查async路由中是否存在同步阻塞逻辑,将同步操作丢到线程池执行即可。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 22:06:27