【NextJS】跨域问题的产生及前端解决方案——本地代理

在使用 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'
    }
  });
}

其他解决策略

  1. 后端支持:跨域资源共享(CORS)

    添加 Access-Control-Allow-Origin

  2. webpack / vite本地代理

  3. 跨文档通信 API:window.postMessage()

    适用于:页面及其打开的新窗口传递数据、多窗口间消息通信、页面与嵌套的iframe消息传递

  4. Nginx 反向代理

    搭建一个中转 nginx 服务器,用于转发请求

  5. WebSocket 全双工通信

参考

  1. https://nextjs.org/docs/pages/building-your-application/routing/api-routes
  2. https://www.cnblogs.com/mochenxiya/p/16597545.html
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值