Java案例如何实现跨域处理?一文详解跨域解决方案与实战代码
目录导读
- 什么是跨域?为什么会出现跨域问题?
- 跨域问题的本质与常见场景分析
- Java后端解决跨域的四大主流方案
- 使用CORS过滤器(最常用)
- Spring框架的@CrossOrigin注解
- JSONP方案(仅限GET请求)
- Nginx反向代理跨域
- 常见问题与问答汇总
- 跨域处理的最佳实践建议
什么是跨域?为什么会出现跨域问题?
跨域(Cross-Origin) 指的是浏览器在请求不同源(协议、域名、端口任一不同)的资源时,出于安全考虑,会限制这种请求,这是浏览器的同源策略(Same-Origin Policy) 所规定的安全机制。

前端部署在 http://localhost:8080,后端接口部署在 http://localhost:8081,这两个地址端口不同,因此属于跨域请求,浏览器会直接拦截响应。
常见跨域场景
| 前端地址 | 后端地址 | 是否跨域 |
|---|---|---|
http://a.com |
http://a.com/api |
否 |
http://a.com |
http://b.com/api |
是(域名不同) |
http://a.com:80 |
http://a.com:8080 |
是(端口不同) |
http://a.com |
https://a.com |
是(协议不同) |
注意:跨域是浏览器行为,服务器之间直接通信不存在跨域问题。
跨域问题的本质与常见场景分析
跨域问题的本质是浏览器阻止了前端JavaScript读取跨域请求的响应内容,实际场景中,跨域通常出现在以下情况:
- 前后端分离开发:前端Vue/React项目运行在localhost:3000,后端Spring Boot运行在localhost:8081
- 微服务架构:多个服务部署在不同域名或端口下
- 第三方API调用:调用外部API时(如百度地图、微信接口)
Java后端解决跨域的四大主流方案
在Java生态中,最常见的四种跨域解决方案:CORS过滤器、@CrossOrigin注解、JSONP、Nginx反向代理,其中CORS过滤器是通用性最强、最推荐的方式。
使用CORS过滤器(最常用)
这是企业级项目中最推荐的跨域处理方式,通过自定义一个Filter,添加响应头来允许跨域访问。
核心原理
CORS(Cross-Origin Resource Sharing)通过在HTTP响应头中添加以下字段实现跨域:
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
Access-Control-Allow-Headers: Content-Type, Authorization
完整Java代码实现
import javax.servlet.*;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@Component
public class CorsFilter implements Filter {
@Override
public void doFilter(ServletRequest servletRequest,
ServletResponse servletResponse,
FilterChain filterChain) throws IOException, ServletException {
HttpServletResponse response = (HttpServletResponse) servletResponse;
// 允许所有域名访问(建议生产环境指定具体域名)
response.setHeader("Access-Control-Allow-Origin", "*");
// 允许的HTTP方法
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
// 允许的自定义请求头
response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With");
// 允许携带Cookie
response.setHeader("Access-Control-Allow-Credentials", "true");
// 预检请求缓存时间(秒)
response.setHeader("Access-Control-Max-Age", "3600");
// 对于OPTIONS预检请求,直接返回200
if ("OPTIONS".equalsIgnoreCase(((HttpServletRequest) servletRequest).getMethod())) {
response.setStatus(HttpServletResponse.SC_OK);
return;
}
filterChain.doFilter(servletRequest, servletResponse);
}
}
配置Filter注册(Spring Boot)
@Configuration
public class WebConfig {
@Bean
public FilterRegistrationBean<CorsFilter> corsFilterRegistration() {
FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new CorsFilter());
registration.addUrlPatterns("/*"); // 拦截所有请求
registration.setName("corsFilter");
registration.setOrder(1);
return registration;
}
}
优点:全局生效,一次配置,所有接口自动支持跨域;支持所有HTTP方法。
缺点:如果前后端都需要指定具体域名,需要额外配置。
Spring框架的@CrossOrigin注解
如果你的项目使用Spring Boot,可以不必写完整的Filter,直接使用@CrossOrigin注解。
在Controller类上加注解(全局)
@RestController
@CrossOrigin(origins = "http://localhost:3000") // 允许前端地址
@RequestMapping("/api")
public class UserController {
@GetMapping("/users")
public List<User> getUsers() {
// 业务逻辑
}
}
在具体方法上加注解(细粒度)
@RestController
@RequestMapping("/api")
public class UserController {
@CrossOrigin(origins = "http://localhost:3000")
@GetMapping("/users")
public List<User> getUsers() {
// 业务逻辑
}
// 其他接口不跨域
@GetMapping("/internal")
public String internal() {
return "内部接口";
}
}
全局配置(WebMvcConfigurer)
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("http://localhost:3000") // 指定来源
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.allowCredentials(true);
}
}
优点:使用简单,Spring官方支持。
缺点:必须在Spring环境中使用;如果在Filter层面还有权限校验,需要确保顺序。
JSONP方案(仅限GET请求)
JSONP是一种古老的跨域解决方案,利用<script>标签不受同源策略限制的特性实现。
JSONP原理
- 前端动态创建一个
<script>标签,src指向后端接口,并带上回调函数名 - 后端返回
callback(JSON数据)的形式 - 浏览器接收到响应后,自动执行回调函数
Java后端实现JSONP
@RestController
@RequestMapping("/api")
public class JsonpController {
@GetMapping("/users")
public String getUsersJsonp(@RequestParam("callback") String callback) {
List<User> users = userService.findAll();
String json = new Gson().toJson(users);
// 返回 callback(json) 格式
return callback + "(" + json + ")";
}
}
前端调用示例(原生):
function jsonpRequest() {
let script = document.createElement('script');
script.src = 'http://localhost:8081/api/users?callback=handleResponse';
document.body.appendChild(script);
}
function handleResponse(data) {
console.log('跨域获取的数据:', data);
}
缺点:
- 只支持GET请求
- 安全性较低(可能被XSS攻击)
- 难以处理错误(404/500等)
建议:除非维护老旧系统,否则不推荐使用JSONP。
Nginx反向代理跨域
如果不想修改后端代码,可以通过Nginx服务器进行代理,同源的请求由Nginx转发到不同后端服务。
Nginx配置示例
server {
listen 80;
server_name api.example.com;
location /api/ {
proxy_pass http://localhost:8081/; # 转发到Java后端
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# 添加CORS头
add_header Access-Control-Allow-Origin *;
add_header Access-Control-Allow-Methods "GET, POST, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type, Authorization";
# 处理OPTIONS预检请求
if ($request_method = 'OPTIONS') {
return 204;
}
}
location /static/ {
alias /var/www/html/; # 前端静态资源目录
}
}
前端访问:直接请求http://api.example.com/api/users即可,不会出现跨域问题。
优点:无需修改后端代码;集中管理跨域策略。
缺点:需要额外部署Nginx;请求路径多一层代理,略微增加延迟。
常见问题与问答汇总
问:为什么有时候配置了CORS还是报跨域错误?
答:常见原因有三个:
- 浏览器同源策略无法禁用:尝试用Postman测试,如果正常则说明CORS配置没问题
- 缺少OPTIONS预检请求处理:浏览器发送跨域请求前会先发OPTIONS请求,后端必须返回204或200
- Allow-Origin与Allow-Credentials冲突:当
allowCredentials(true)时,allowedOrigins不能是,必须指定具体域名
问:前端使用axios时,跨域需要额外配置吗?
答:不需要额外配置axios,但需要注意:
- 如果后端设置了
withCredentials: true,前端axios也需要配置axios.defaults.withCredentials = true - 如果后端
allowedOrigins指定了具体域名,前端请求的URL必须与之一致(区分http和https)
问:跨域和CSRF(跨站请求伪造)有关系吗?
答:有关系,跨域请求本身是浏览器行为,而CSRF攻击利用了用户的登录凭证,CORS配置中如果开启了allowCredentials(true),需要配合CSRF防护机制(如添加CSRF Token、SameSite属性等),防止恶意网站利用Cookie发起跨域请求。
问:生产环境下,allowedOrigins应该配置还是具体域名?
答:强烈建议配置具体域名,允许所有来源访问,包括恶意网站,如果API涉及用户认证(Cookie/Token),绝不能使用,否则会造成严重安全漏洞,正确做法:线上环境将前端部署域名写入白名单。
跨域处理的最佳实践建议
- 优先使用CORS过滤器方案:通用性强,不依赖框架,适合所有Java Web项目
- 区分开发环境和生产环境:
- 开发环境:
allowedOrigins可配置或前端开发地址(如http://localhost:3000) - 生产环境:务必配置具体域名,且保持与前端部署域名一致
- 开发环境:
- 不要忘记处理OPTIONS请求:预检请求是CORS实现的关键环节
- 结合Nginx反向代理:如果公司已有网关服务(Nginx/Kong/Spring Cloud Gateway),将跨域处理放在网关层更合理,后端的Java服务只需关注业务逻辑
- 安全优先:开启凭证时(allowCredentials=true),务必指定具体来源,并配合CSRF防护
Java后端跨域处理并不复杂,核心在于理解CORS协议,建议刚入门的开发者直接使用方案一(CORS Filter) 或方案二的全局配置作为企业级开发标配,同时保留Nginx反向代理作为运维备选方案,在实际项目中,根据团队技术栈和安全要求,选择合适的方案即可。