跨域问题详解:Spring MVC + Nginx + Axios 全链路解决方案

跨域问题(CORS,Cross-Origin Resource Sharing)是 Web 研发中常见问题。当浏览器从一个源(origin)向另一个源发起请求时,出于安全思考,会受到同源策略(Same-Origin Policy)的限制。

本文将从 Spring MVC配置 + Nginx 配置 + Axios 前端调用最常规的组合解析如果通过配置解决跨域问题。


一、Spring MVC 服务端配置 CORS

方法 1:使用 @CrossOrigin注解(适用于单个 Controller 或方法)

@RestController
@CrossOrigin(origins = "http://localhost:3000") // 允许来自该源的请求
public class MyController {

    @GetMapping("/api/data")
    public String getData() {
        return "Hello CORS";
    }
}
  • origins:指定允许的源,可以是数组(多个源),也可以是 “*”(不推荐用于带凭证的请求)
  • 也可以加在方法上,粒度更细

方法 2:全局配置(推荐)

方式 A:通过 WebMvcConfigurer实现

@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**") // 匹配需要跨域的路径
                .allowedOrigins("http://localhost:3000") // 允许的源
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                .allowCredentials(true) // 是否允许携带 Cookie
                .maxAge(3600); // 预检请求缓存时间(秒)
    }
}

⚠️ 注意:如果 allowCredentials(true),则 allowedOrigins 不能为 “*”,必须指定具体域名。

方式 B:通过 CorsFilter(更底层,适用于所有请求)

ounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(lineounter(line
@Bean
public CorsFilter corsFilter() {
    CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("http://localhost:3000");
    config.addAllowedHeader("*");
    config.addAllowedMethod("*");

    UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    source.registerCorsConfiguration("/**", config); // 对所有路径生效

    return new CorsFilter(source);
}

二、Nginx 配置 CORS(作为反向代理)

如果你使用 Nginx 作为反向代理(例如前端部署在 Nginx,后端 API 也通过 Nginx 代理),可以在 Nginx 层统一处理 CORS,减轻后端压力。

示例配置:

server {
    listen 80;
    server_name your-domain.com;

    location /api/ {
        # 添加 CORS 头
        add_header 'Access-Control-Allow-Origin' 'http://localhost:3000' always;
        add_header 'Access-Control-Allow-Credentials' 'true' always;
        add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS' always;
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;

        # 处理预检请求(OPTIONS)
        if ($request_method = 'OPTIONS') {
            add_header 'Access-Control-Max-Age' 1728000;
            add_header 'Content-Type' 'text/plain; charset=utf-8';
            add_header 'Content-Length' 0;
            return 204;
        }

        # 代理到后端 Spring Boot 服务
        proxy_pass http://backend-server:8080/;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

关键点

always 参数确保即使 4xx/5xx 响应也包含 CORS 头。

OPTIONS 请求必须返回 204,否则浏览器会报错。

如果后端已经处理了 CORS,Nginx 不要重复设置,避免冲突(尤其是
Access-Control-Allow-Origin 重复)。


三、前端 Axios 配置

1. 基本请求(不带凭证)

axios.get('http://your-api.com/api/data')
  .then(res => console.log(res))
  .catch(err => console.error(err));

2. 携带 Cookie / 认证信息(需前后端配合)


axios.get('http://your-api.com/api/data', {  withCredentials: true  // 关键:允许跨域携带 Cookie
})

⚠️ 注意:

如果使用 withCredentials: true,服务端必须设置
Access-Control-Allow-Credentials: true


Access-Control-Allow-Origin
不能为 *,必须是具体域名(如 http://localhost:3000)

3. 自定义请求头(会触发预检 OPTIONS 请求)

axios.post('http://your-api.com/api/data', { name: 'test' }, {
  headers: {
    'Authorization': 'Bearer xxx',
    'Content-Type': 'application/json'
  },
  withCredentials: true
})

四、常见问题排查

问题

缘由

解决方案

CORS header ‘Access-Control-Allow-Origin’ missing

服务端未返回 CORS 头

检查 Spring 或 Nginx 配置

Credentials flag is ‘true’, but the ‘Access-Control-Allow-Origin’ header is ‘*’

withCredentials=true

但 origin 为 *

改为具体域名

Preflight response is not successful

OPTIONS 请求未正确处理

确保服务端或 Nginx 返回 204 并包含 CORS 头

Nginx 配置了 CORS 但无效

后端也返回了 CORS 头导致冲突

只保留一处(提议统一在 Nginx 或后端)


五、最佳实践提议

场景

推荐方案

开发环境

Spring MVC 全局 addCorsMappings,快速调试

生产环境

Nginx 反向代理 + 统一 CORS 配置,安全可控

前端开发

使用 Axios 实例封装,配置 withCredentials 和 baseURL

✅ 终极提议:在生产环境中,不要依赖后端直接处理跨域,而是通过 Nginx 反向代理,让前后端“看起来”是同源的,这才是最安全、最稳定的方案。

© 版权声明
THE END
如果内容对您有所帮助,就支持一下吧!
点赞0 分享
评论 共1条

请登录后发表评论