前端跨域解决方案
在前端开发过程中,跨域(CORS)是一个常见问题。本文档介绍使用 Lovrabet CLI 创建的项目中,如何解决跨域问题的多种方案。
什么是跨域问题?
跨域是指浏览器出于安全考虑,限制从一个域名的网页去请求另一个域名的资源。当协议、域名或端口不同时,就会产生跨域问题。
重要说明:即使都是 *.lovrabet.com 的子域名,dev.lovrabet.com 和 api.lovrabet.com 仍然是不同的域名,属于跨域请求。只是通过配置 CORS 白名单,允许了这种跨域访问。
跨域判断标准
浏览器判断是否跨域,主要看以下三个要素是否完全相同:
- 协议(Protocol):
httpvshttps - 域名(Domain):
dev.lovrabet.comvsapi.lovrabet.com - 端口(Port):
80vs443vs3000
跨域示例
| 前端地址 | API 地址 | 是否跨域 | 说明 |
|---|---|---|---|
http://localhost:3000 | https://api.lovrabet.com | 跨域 | 协议、域名、端口都不同 |
https://dev.lovrabet.com | https://api.lovrabet.com | 跨域 | 域名不同(虽然都是 lovrabet.com 子域) |
https://dev.lovrabet.com | https://dev.lovrabet.com | 同域 | 完全相同的域名 |
http://example.com:80 | http://example.com:443 | 跨域 | 端口不同 |
https://example.com | http://example.com | 跨域 | 协议不同 |
注意:dev.lovrabet.com → api.lovrabet.com 虽然都是 lovrabet.com 的子域名,但仍然是跨域。只是通过服务器端配置 CORS 白名单,允许了这种跨域访问,所以不会出现跨域错误。
解决方案概览
Lovrabet CLI 提供了多种解决跨域问题的方案,你可以根据实际场景选择:
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 方案1:使用 dev.lovrabet.com | 开发阶段 | 自动配置,无需额外设置 | 仅限开发环境 |
| 方案2:服务器 CORS 配置 | 需要访问自有 API | 简单直接 | 需要服务器权限 |
| 方案3:服务器转发 | 复杂业务场景 | 灵活可控,可添加业务逻辑 | 需要额外开发 |
| 方案4:独立部署 | 生产环境 | 完全自主,无跨域问题 | 需要部署资源 |
方案 1:使用 dev.lovrabet.com 开发域名(推荐)
工作原理
使用 lovrabet start 启动项目时,CLI 会自动将你的本地项目映射到 dev.lovrabet.com 开发域名。
重要:dev.lovrabet.com 和 api.lovrabet.com 虽然都是 lovrabet.com 的子域名,但仍然是不同的域名,属于跨域请求。只是 dev.lovrabet.com 已经加入了 Lovrabet 平台的 CORS 白名单,服务器端允许了来自 dev.lovrabet.com 的跨域请求,所以不会出现跨域错误。
使用方法
# 启动开发服务器
lovrabet start
# 访问地址会自动映射到
# https://dev.lovrabet.com/your-app-path
优势
- ✅ 零配置:无需任何额外设置,开箱即用
- ✅ 自动映射:CLI 自动处理域名映射和 HTTPS
- ✅ 白名单已配置:
dev.lovrabet.com已加入跨域白名单 - ✅ 开发友好:支持热更新,开发体验流畅
注意事项
- 此方案仅适用于开发环境
- 需要登录 Lovrabet 平台才能使用
dev.lovrabet.com域名 - 如果访问非
*.lovrabet.com的 API,仍可能出现跨域问题
方案 2:服务器 CORS 配置
适用场景
当你的前端应用运行在 dev.lovrabet.com,但需要访问自己服务器的 API 时,可能遇到跨域问题。此时可以在自己的服务器上配置 CORS,允许 dev.lovrabet.com 访问。
配置示例
Node.js (Express)
const express = require('express');
const app = express();
// 允许 dev.lovrabet.com 跨域访问
app.use((req, res, next) => {
res.header('Access-Control-Allow-Origin', 'https://dev.lovrabet.com');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
if (req.method === 'OPTIONS') {
return res.sendStatus(200);
}
next();
});
Nginx
server {
listen 80;
server_name your-api-domain.com;
location / {
# 允许 dev.lovrabet.com 跨域访问
add_header 'Access-Control-Allow-Origin' 'https://dev.lovrabet.com';
add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'Content-Type, Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
if ($request_method = 'OPTIONS') {
return 204;
}
# 你的 API 处理逻辑
proxy_pass http://backend;
}
}
Spring Boot (Java)
@Configuration
public class CorsConfig {
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://dev.lovrabet.com")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
};
}
}
优势
- ✅ 简单直接:只需在服务器端配置一次
- ✅ 性能好:浏览器直接访问 API,无中间层
- ✅ 灵活:可以精确控制允许的域名和方法
注意事项
- 需要服务器管理员权限
- 生产环境建议使用环境变量配置允许的域名
- 注意安全性,不要使用通配符
*允许所有域名
方案 3:服务器转发请求(API 中转)
适用场景
当无法修改服务器 CORS 配置,或者需要在请求中添加业务逻辑、权限验证、数据转换时,可以使用服务器转发方案。
工作原理
前端不直接调用目标 API,而是调用自己的服务器接口,由服务器转发请求到目标 API。这样可以:
- 绕过浏览器的跨域限制
- 在服务器端添加业务逻辑
- 隐藏 API 实现细节
- 统一错误处理和日志记录
实现示例
参考 Next.js 演示项目 中的场景 3:API 中转方案。
Next.js API Route 示例
// app/api/proxy/data/route.ts
import { NextRequest, NextResponse } from "next/server";
import { createServerClient } from "@/lib/sdk-client";
export async function GET(request: NextRequest) {
try {
const searchParams = request.nextUrl.searchParams;
const page = searchParams.get("page") || "1";
const size = searchParams.get("size") || "10";
// 在服务器端创建客户端(无跨域问题)
const client = createServerClient();
const model = client.getModel(0);
// 调用 SDK 获取数据
const response = await model.filter({
page: parseInt(page),
pageSize: parseInt(size),
});
// 返回数据给前端
return NextResponse.json({
success: true,
data: response,
});
} catch (error) {
return NextResponse.json(
{
success: false,
error: error instanceof Error ? error.message : "Unknown error",
},
{ status: 500 }
);
}
}
前端调用
// 前端通过自己的 API 路由获取数据
const fetchData = async () => {
const response = await fetch('/api/proxy/data?page=1&size=10');
const result = await response.json();
if (result.success) {
// 使用数据
console.log(result.data);
}
};
Express.js 示例
const express = require('express');
const axios = require('axios');
const app = express();
app.use(express.json());
// 代理 API 请求
app.get('/api/proxy/data', async (req, res) => {
try {
const { page, size } = req.query;
// 在服务器端调用目标 API(无跨域限制)
const response = await axios.get('https://api.target.com/data', {
params: { page, size },
headers: {
'Authorization': `Bearer ${process.env.API_TOKEN}`,
},
});
// 可以在这里添加业务逻辑、数据转换等
const transformedData = transformData(response.data);
res.json({
success: true,
data: transformedData,
});
} catch (error) {
res.status(500).json({
success: false,
error: error.message,
});
}
});
function transformData(data) {
// 数据转换逻辑
return data;
}
优势
- ✅ 完全绕过跨域:服务器端无跨域限制
- ✅ 灵活可控:可以添加业务逻辑、权限验证
- ✅ 隐藏实现:前端不需要知道目标 API 的细节
- ✅ 统一处理:可以统一错误处理、日志记录、缓存等
注意事项
- 需要额外的服务器资源
- 增加了请求链路,可能有轻微延迟
- 需要处理服务器端的错误和超时
完整示例
查看完整的实现示例:openapi-nextjs-demo 项目中的 scenario3-proxy 场景。
方案 4:独立部署到自己的服务器
适用场景
开发完成后,将项目独立部署到自己的服务器,使用自己的域名。这样就不会有跨域问题,因为前端和 API 都在你的控制范围内。
部署步骤
1. 构建生产版本
# 构建项目
lovrabet build
# 构建产物在 dist/ 目录
2. 部署到服务器
将 dist/ 目录的内容部署到你的 Web 服务器(Nginx、Apache、CDN 等)。
3. 配置域名和 HTTPS
# Nginx 配置示例
server {
listen 80;
server_name your-domain.com;
# 重定向到 HTTPS
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl;
server_name your-domain.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
root /path/to/dist;
index index.html;
location / {
try_files $uri $uri/ /index.html;
}
}
4. 配置 API 地址
在项目配置中设置生产环境的 API 地址:
// .env.production
VITE_API_BASE_URL=https://api.your-domain.com
优势
- ✅ 完全自主:完全控制前端和 API
- ✅ 无跨域问题:同域名或已配置 CORS
- ✅ 性能最优:直接访问,无中间层
- ✅ 生产就绪:适合生产环境使用
注意事项
- 需要服务器资源和域名
- 需要配置 HTTPS 证书
- 需要处理路由和静态资源
- 建议使用 CDN 加速静态资源
方案选择建议
根据你的实际场景选择合适的方案:
| 开发阶段 | 推荐方案 | 说明 |
|---|---|---|
| 本地开发 | 方案 1:dev.lovrabet.com | 零配置,开箱即用 |
| 需要访问自有 API | 方案 2:服务器 CORS | 简单直接,性能好 |
| 复杂业务场景 | 方案 3:服务器转发 | 灵活可控,功能强大 |
| 生产环境 | 方案 4:独立部署 | 完全自主,性能最优 |
常见问题
Q: 为什么使用 dev.lovrabet.com 不会跨域?
A: 实际上 dev.lovrabet.com 和 api.lovrabet.com 仍然是跨域(因为域名不同)。但 dev.lovrabet.com 已经加入了 Lovrabet 平台的 CORS 白名单,服务器端配置了允许来自 dev.lovrabet.com 的跨域请求,所以浏览器不会阻止这些请求,看起来就像没有跨域问题一样。
Q: 可以在本地 localhost 开发吗?
A: 可以,但 localhost 不在跨域白名单中,访问 *.lovrabet.com 的 API 会出现跨域问题。建议使用 dev.lovrabet.com 进行开发。
Q: 生产环境必须独立部署吗?
A: 不一定。如果你的前端和 API 都在同一域名下,或者已经配置了 CORS,也可以直接部署。但独立部署通常更灵活、更安全。
Q: 服务器转发会影响性能吗?
A: 会有轻微影响,因为增加了请求链路。但对于大多数应用来说,这个影响可以忽略不计。如果对性能要求极高,建议使用方案 2 或方案 4。