在使用 React / Next.js 开发时,调用后端接口往往会遇到跨域问题。本文章旨在记录升级开源云操作系统 Sealos 数据库系统界面时遇到的跨域错误及解决方案
什么是跨域
「跨域」是指游览器出于安全策略(同源策略,Same-Origin-Policy)的限制,阻止网页去请求另一个「源」的资源。
所谓「源」是指:
- 协议
- 域名
- 端口
只要其中一个不同,就是跨域
跨域场景
React 会在如 localhost:3000 启动一个开发服务器,此时直接请求第三方 API,游览器会进行 CORS(Cross-Origin Resource Sharing)检查,如果第三方 API 没有正确设置 Access-Control-Allow-Origin、Access-Control-Allow-Headers(如 Authorization),浏览器会阻止请求,报 CORS 错误,如:
解决方案本地代理
核心思路:让前端请求自己的本地 Next.js API 路由,由本地服务端再去请求第三方 API,
这样浏览器和本地 API 没有跨域问题,本地 API 和第三方 API 之间也没有 CORS 限制
1. 新建本地代理 API 路由
在 Next.js 目录中创建 pages/api,因为 pages/api 文件夹中的任何文件都会映射到 /api/*,并将被视为 API 端点(而非页面)
Next.js 官方文档的模版代码,以下 API 路由返回状态代码为 200 的 JSON 响应
import type { NextApiRequest, NextApiResponse } from 'next'
type ResponseData = {
message: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<ResponseData>
) {
res.status(200).json({ message: 'Hello from Next.js!' })
}
举个项目中的实际列子:
import type { NextApiRequest, NextApiResponse } from 'next';
// 匿名导出 handler 函数
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
if (req.method !== 'POST') { // 仅处理 POST 请求
res.status(405).end();
return;
}
const apiUrl = 'https://chat2dbgateway.sealosbja.site/api/open/enterprise/sync_auth_user_a';
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
...(req.headers.authorization ? { 'Authorization': req.headers.authorization } : {}),
'Time-Zone': Array.isArray(req.headers['time-zone'])
? req.headers['time-zone'][0]
: req.headers['time-zone'] || 'Asia/Shanghai'
},
body: JSON.stringify(req.body)
});
// 返回结果给客户端
const data = await response.json();
res.status(response.status).json(data);
}
2. 前端调用本地代理接口
export function createDatasource(
data: Omit<DatasourceForm, 'id'>,
apiKey: string,
userKey: string
) {
return POST<CreateApiResponse>('/api/proxy/create_data_source_a', data, {
headers: {
Authorization: `Bearer ${apiKey}`,
auth_user: userKey,
'Time-Zone': 'Asia/Shanghai',
'Content-Type': 'application/json'
}
});
}
其他解决策略
-
后端支持:跨域资源共享(CORS)
添加 Access-Control-Allow-Origin
-
webpack / vite本地代理
-
跨文档通信 API:window.postMessage()
适用于:页面及其打开的新窗口传递数据、多窗口间消息通信、页面与嵌套的iframe消息传递
-
Nginx 反向代理
搭建一个中转 nginx 服务器,用于转发请求
-
WebSocket 全双工通信
参考
- https://nextjs.org/docs/pages/building-your-application/routing/api-routes
- https://www.cnblogs.com/mochenxiya/p/16597545.html