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

Next.js 14客户端组件如何无需配置跨域调用外部API?

问题:Next.js 14客户端组件fetch请求CORS错误解决方法

我正在使用Next.js 14 App Router,了解可在Server Component中通过Server Actions获取数据,但因某些原因,特定路由的page.tsx必须为客户端组件。尝试在客户端组件中使用useEffect()结合fetch()调用外部API端点时,尽管目标服务器已允许所有源请求,仍在控制台出现CORS错误:

Access to fetch at 'http://localhost:9000/endpoint' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

同时Next.js错误面板显示:

Unhandled Runtime Error
TypeError: Failed to fetch

但通过Server Actions使用相同fetch()调用同一端点却能成功。目前可通过在next.config.js中配置rewrites临时解决:

/** @type {import('next').NextConfig} */
const nextConfig = {
    async rewrites() {
      return [
        {
          source: "/endpoint",
          destination:
            "https://exampleapi.com/endpoint",
        },
      ];
    },
};

module.exports = nextConfig;

该方法可解决CORS及“Failed to fetch”运行时错误,但需为每个端点单独配置。请问是否存在无需修改next.config.js,在客户端组件的useEffect中使用fetch()获取数据的其他方法?


解决方案

方法1:在客户端组件中调用Server Action(推荐)

既然Server Action能绕过CORS成功调用API,直接在客户端组件中复用这个逻辑即可,无需自行编写客户端fetch请求。

首先定义Server Action(放在单独的文件中,需添加'use server'指令):

'use server';

export async function fetchExternalData() {
  const res = await fetch('http://localhost:9000/endpoint', {
    method: 'GET', // 匹配目标API的请求方法
    // 保留你之前Server Action中成功的配置(如请求头、认证信息等)
  });
  
  if (!res.ok) {
    throw new Error('获取数据失败');
  }
  
  return res.json();
}

然后在客户端组件中调用该Server Action:

'use client';

import { fetchExternalData } from '@/app/actions';
import { useEffect, useState } from 'react';

export default function ClientPage() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    const getData = async () => {
      try {
        const result = await fetchExternalData();
        setData(result);
      } catch (err) {
        setError(err.message);
      }
    };
    getData();
  }, []);

  if (error) return <div>错误:{error}</div>;
  if (!data) return <div>加载中...</div>;
  return <div>数据:{JSON.stringify(data)}</div>;
}

此方案通过服务器端发起请求,完全规避浏览器的CORS限制,且无需修改配置文件。

方法2:使用Next.js API Route作为通用代理

创建一个通用的代理API端点,可处理多个外部API请求,无需逐个配置rewrites。

在app/api/proxy/route.ts中创建代理逻辑:

export async function GET(request: Request) {
  const urlParams = new URL(request.url).searchParams;
  const targetUrl = urlParams.get('url');
  
  if (!targetUrl) {
    return new Response('缺少目标URL参数', { status: 400 });
  }

  try {
    const res = await fetch(targetUrl, {
      // 根据需求传递请求头、认证信息等
      headers: {
        'Content-Type': 'application/json',
      },
      cache: 'no-store', // 避免缓存,按需调整
    });

    const responseData = await res.json();
    return new Response(JSON.stringify(responseData), {
      status: res.status,
      headers: {
        'Content-Type': 'application/json',
      },
    });
  } catch (err) {
    return new Response('代理请求失败', { status: 500 });
  }
}

然后在客户端组件的useEffect中调用这个代理端点:

'use client';

import { useEffect, useState } from 'react';

export default function ClientPage() {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    const getData = async () => {
      try {
        const targetApi = 'http://localhost:9000/endpoint';
        const res = await fetch(`/api/proxy?url=${encodeURIComponent(targetApi)}`);
        
        if (!res.ok) {
          throw new Error('代理请求失败');
        }
        
        const result = await res.json();
        setData(result);
      } catch (err) {
        setError(err.message);
      }
    };
    getData();
  }, []);

  // 渲染逻辑同前
}

该方案只需创建一个代理端点,即可支持任意外部API请求,无需修改next.config.js。

方法3:排查目标服务器CORS配置(若有权限修改)

若你有权限调整目标服务器配置,可检查以下几点:

  • 确认服务器返回Access-Control-Allow-Origin: *(或明确包含http://localhost:3000)
  • 针对带自定义请求头或非GET/POST的请求,服务器需正确处理OPTIONS预请求,返回Access-Control-Allow-Methods、Access-Control-Allow-Headers等响应头
  • 重启服务器,确保新的CORS配置生效

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.03 15:52:46