跨域解决方案


一、什么是跨域?

跨域是指浏览器在发起请求时,请求的协议、域名、端口三者中,只要有一个与当前页面的地址不同,就会被浏览器拦截。

判断规则

以当前页面 http://localhost:8080 为例:

请求地址 是否跨域 原因
http://localhost:8080/api ❌ 同源 协议、域名、端口完全一致
https://localhost:8080/api ✅ 跨域 协议不同(http vs https)
http://api.example.com/api ✅ 跨域 域名不同
http://localhost:3000/api ✅ 跨域 端口不同(8080 vs 3000)

跨域的本质

跨域不是后端拒绝了你,是浏览器拦截了响应。

浏览器发请求 → 后端正常处理并返回数据 → 浏览器检查是否跨域
                                                ↓
                                        跨域 → 浏览器拦截数据,抛错
                                        同源 → 正常交给前端代码

为什么要有跨域限制?

浏览器的同源策略,是为了保护用户安全。举个例子:

你登录了 bank.com,浏览器保存了登录 Cookie
    ↓
你不小心打开了 hacker.com
    ↓
如果没有同源策略,hacker.com 的 JS 可以:
  - 读取 bank.com 的 Cookie
  - 伪造转账请求
  - 窃取你的账户信息

同源策略就是浏览器的安全门卫,防止恶意网站窃取数据。


二、怎么解决跨域?

方案一:后端配置 CORS(最推荐,生产首选)

原理:后端在响应头中告诉浏览器:“这个跨域请求是我允许的,放行。”

Spring Boot 配置方式

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")                    // 允许跨域的路径
                .allowedOriginPatterns("*")               // 允许所有来源(生产环境建议指定具体域名)
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true)                   // 允许携带 Cookie
                .maxAge(3600);                            // 预检请求缓存时间(秒)
    }
}

Nginx 配置方式

server {
    listen 80;
    server_name api.example.com;
    
    location / {
        add_header Access-Control-Allow-Origin *;
        add_header Access-Control-Allow-Methods 'GET, POST, PUT, DELETE, OPTIONS';
        add_header Access-Control-Allow-Headers 'Content-Type, Authorization';
        
        if ($request_method = 'OPTIONS') {
            return 204;
        }
        
        proxy_pass http://localhost:8080;
    }
}

方案二:前端代理(开发环境首选)

原理:前端请求同源的代理服务器,代理服务器转发到后端(服务器间通信不受同源策略限制)。

Vue 项目配置(vue.config.js)

module.exports = {
    devServer: {
        proxy: {
            '/api': {
                target: 'http://localhost:8090',  // 后端地址
                changeOrigin: true,
                pathRewrite: {
                    '^/api': ''
                }
            }
        }
    }
}

React 项目配置(setupProxy.js)

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
    app.use(
        '/api',
        createProxyMiddleware({
            target: 'http://localhost:8090',
            changeOrigin: true,
        })
    );
};

方案三:Nginx 反向代理(生产环境首选)

原理:前端和 Nginx 同源,Nginx 转发请求到后端,浏览器不感知跨域。

server {
    listen 80;
    server_name www.example.com;
    
    # 前端静态文件
    root /var/www/html;
    index index.html;
    
    # 反向代理后端接口
    location /api/ {
        proxy_pass http://localhost:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
    
    # 处理前端路由(history 模式)
    location / {
        try_files $uri $uri/ /index.html;
    }
}

三、三种方案对比

方案 适用环境 优点 缺点
后端 CORS 生产环境 配置简单,标准方案 需要后端配合
前端代理 开发环境 无需后端配合,快速调试 仅开发环境有效
Nginx 反向代理 生产环境 隐藏后端地址,性能好 需要运维配置

四、常见踩坑点

问题 原因 解决方案
allowedOrigins("*") 报错 allowCredentials(true) 冲突 改用 allowedOriginPatterns("*")
OPTIONS 请求返回 403 后端没处理预检请求 在拦截器中放行 OPTIONS 请求
带 Cookie 跨域失败 前端没设置 withCredentials: true 前端设置 axios.defaults.withCredentials = true
生产环境跨域 前端代理只在开发环境生效 改用 Nginx 反向代理或后端 CORS

五、一句话总结

跨域是浏览器同源策略导致的拦截,不是后端的问题。解决方案有三种:后端配 CORS(生产推荐)、前端配代理(开发推荐)、Nginx 反向代理(生产推荐)。记住核心原则:跨域问题必须由服务端解决,前端代码改不了。

posted @ 2026-05-13 04:14  圣祖帝皇  阅读(30)  评论(0)    收藏  举报