Next.js 13.2.3调用本地ASP.NET Web API遇TypeError: fetch failed问题
问题:Next.js 13.2.3 调用本地ASP.NET Web API 出现 TypeError: fetch failed
本地有两个独立项目:前端使用Next.js 13.2.3,后端为ASP.NET Web API。后端API通过Swagger UI测试正常,前端能正常获取https://jsonplaceholder.typicode.com/users的数据,但调用本地后端API时抛出TypeError: fetch failed错误。已在后端配置CORS允许前端地址http://127.0.0.1:3000,且该后端在基于Vite的React项目中可正常调用。
后端CORS配置代码(Program.cs)
using Microsoft.EntityFrameworkCore; using PropertyManagerWebAPI.Models; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); #region Set up Cors policy to be able to to talk to React client var provider = builder.Services.BuildServiceProvider(); var configuration = provider.GetRequiredService<IConfiguration>(); builder.Services.AddCors(options => { var frontendUrl = configuration.GetValue<string>("frontend_url"); options.AddDefaultPolicy(builder => { builder.WithOrigins(frontendUrl).AllowAnyMethod().AllowAnyHeader(); }); }); #endregion //Dependency Injection of DbContext Class builder.Services.AddDbContext<APIDbContext>(options => options.UseSqlServer(builder.Configuration.GetConnectionString("DevConnection"))); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseCors(); app.UseAuthorization(); app.MapControllers(); app.Run();
前端调用代码(src\app\dashboard\page.tsx)
async function getData() { const response = await fetch("https://127.0.0.1:7227/api/Properties") if (!response.ok) { throw new Error('Failed to fetch data'); } return response.json() } export default async function ProductsPage() { const a: any = await getData() return ( <> <div> {a.map((info: any) => <div key={info.id}> {info.city} </div> )} </div> </> ) }
浏览器错误信息
Uncaught TypeError: fetch failed at Object.fetch (C:\Users\bob\Desktop\all_important\myproject\node_modules\.pnpm\next@13.2.3_biqbaboplfbrettd7655fr4n2y\node_modules\next\dist\compiled\undici\index.js:1:26686) at processTicksAndRejections (node:internal/process/task_queues:96:5)
The above error occurred in the <RedirectErrorBoundary> component: at RedirectErrorBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:361:9) at RedirectBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:368:11) at NotFoundBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:404:11) at LoadingBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:317:11) at ErrorBoundaryHandler (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:59:9) at ErrorBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:72:11) at RenderFromTemplateContext (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/render-from-template-context.js:12:34) at OuterLayoutRouter (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:23:11) at section at ScrollAndFocusHandler (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:153:1) at InnerLayoutRouter (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:195:11) at RedirectErrorBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:361:9) at RedirectBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:368:11) at NotFoundErrorBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:397:9) at NotFoundBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:404:11) at LoadingBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:317:11) at ErrorBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:72:11) at RenderFromTemplateContext (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/render-from-template-context.js:12:34) at OuterLayoutRouter (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/layout-router.js:23:11) at body at html at ReactDevOverlay (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/react-dev-overlay/internal/ReactDevOverlay.js:61:9) at HotReload (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/react-dev-overlay/hot-reloader-client.js:20:11) at Router (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/app-router.js:48:11) at ErrorBoundaryHandler (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:59:9) at ErrorBoundary (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/error-boundary.js:72:11) at AppRouter (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/components/app-router.js:24:13) at ServerRoot (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/app-index.js:126:11) at RSCComponent at Root (webpack-internal:///(app-client)/./node_modules/.pnpm/next@13.2.3_biqbaboplfbrettd7655fr4n2y/node_modules/next/dist/client/app-index.js:143:11) React will try to recreate this component tree from scratch using the error boundary you provided, ErrorBoundaryHandler.
怀疑同一localhost运行两个服务导致问题,替换公共API可正常运行,换npm创建新项目问题依旧。
解决方法
1. 处理服务器端证书信任问题
Next.js 13 App Router的页面默认是服务器组件,fetch请求会在Node.js服务器环境执行。本地ASP.NET Web API的自签名HTTPS证书未被Node.js信任,导致请求失败。
- 操作步骤:
- 导出ASP.NET Web API的自签名证书:浏览器访问
https://127.0.0.1:7227,点击地址栏锁图标 → 证书 → 详细信息 → 复制到文件,选择Base64编码格式保存。 - 将证书添加到系统信任列表:
- Windows:运行
certutil -addstore -f "ROOT" 证书文件路径.cer - macOS:运行
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain 证书文件路径.cer - Linux:将证书复制到
/usr/local/share/ca-certificates/,执行sudo update-ca-certificates
- Windows:运行
- 导出ASP.NET Web API的自签名证书:浏览器访问
2. 改为客户端组件执行请求
如果不想处理证书信任,可将页面改为客户端组件,让fetch在浏览器端执行(浏览器通常已信任本地自签名证书):
'use client' import { useState, useEffect } from 'react' async function getData() { const response = await fetch("https://127.0.0.1:7227/api/Properties") if (!response.ok) { throw new Error('Failed to fetch data'); } return response.json() } export default function ProductsPage() { const [data, setData] = useState<any[]>([]) const [error, setError] = useState<string | null>(null) useEffect(() => { const fetchData = async () => { try { const res = await getData() setData(res) } catch (err) { setError((err as Error).message) } } fetchData() }, []) if (error) return <div>Error: {error}</div> if (!data.length) return <div>Loading...</div> return ( <> <div> {data.map((info) => <div key={info.id}> {info.city} </div> )} </div> </> ) }
3. 验证CORS配置细节
- 确认
appsettings.Development.json中的frontend_url值为http://127.0.0.1:3000(末尾不要加斜杠)。 - 临时放宽CORS策略测试:
options.AddDefaultPolicy(builder => { builder.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader(); });
测试通过后再恢复严格的CORS配置。
4. 统一地址格式
前后端使用一致的地址标识:要么都用localhost,要么都用127.0.0.1,避免DNS解析或跨域标识不匹配的问题。
内容的提问来源于stack exchange,提问作者createandlove
相关产品推荐
相关产品推荐

