Java跨域处理完整案例
什么是跨域问题
当浏览器发起AJAX请求时,如果请求的URL与当前页面的协议、域名、端口任一不同,就产生了跨域,浏览器出于安全考虑,默认会阻止跨域请求。

跨域示例:
- 页面地址:
http://localhost:8080 - 请求地址:
http://localhost:9090/api/data
解决方案对比
| 方案 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| CORS过滤器 | Spring Boot/Spring MVC | 简单、无需改动业务代码 | 需要服务端配合 |
| @CrossOrigin注解 | 单个Controller/方法 | 精确控制 | 需要逐类/方法配置 |
| 代理转发 | 前后端分离开发 | 无需服务端配置 | 仅限开发环境 |
| JSONP | 老项目 | 兼容性好 | 只支持GET请求 |
完整案例实现
1 CORS全局配置(推荐)
实现WebMvcConfigurer接口
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // 匹配所有路径
.allowedOriginPatterns("*") // 允许所有来源
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowedHeaders("*")
.exposedHeaders("Authorization", "Content-Type")
.allowCredentials(true) // 允许携带Cookie
.maxAge(3600); // 预检请求缓存时间(秒)
}
}
使用CorsFilter(更底层)
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 允许的域名,可以使用通配符*
config.setAllowedOriginPatterns(Arrays.asList(
"http://localhost:8080",
"http://localhost:3000",
"https://*.example.com"
));
// 允许的请求头
config.setAllowedHeaders(Arrays.asList(
"Authorization",
"Content-Type",
"X-Requested-With",
"Accept",
"Origin",
"Access-Control-Request-Method",
"Access-Control-Request-Headers"
));
// 暴露的响应头
config.setExposedHeaders(Arrays.asList(
"Authorization",
"Content-Type",
"X-Session-Id"
));
// 允许的请求方法
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH"));
// 是否允许携带凭证(Cookie等)
config.setAllowCredentials(true);
// 预检请求的缓存时间
config.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
2 自定义跨域拦截器
@Component
public class CorsInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 设置响应头,允许跨域访问
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
response.setHeader("Access-Control-Allow-Headers", "Authorization, Content-Type");
response.setHeader("Access-Control-Allow-Credentials", "true");
response.setHeader("Access-Control-Max-Age", "3600");
// 处理预检请求
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
response.setStatus(HttpStatus.OK.value());
return false; // 不继续处理
}
return true;
}
}
3 注解方式(精确控制)
@RestController
@RequestMapping("/api")
// 类级别的跨域配置
@CrossOrigin(origins = "http://localhost:8080", maxAge = 3600)
public class UserController {
// 方法级别的跨域配置(优先级高于类级别)
@GetMapping("/users")
@CrossOrigin(
origins = {"http://localhost:8080", "http://localhost:3000"},
allowedHeaders = {"*"},
methods = {RequestMethod.GET, RequestMethod.POST}
)
public List<User> getUsers() {
return userService.findAll();
}
@PostMapping("/login")
public Result login(@RequestBody LoginRequest request) {
// 登录逻辑
return Result.success();
}
}
4 Spring Security集成方案
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.cors().and() // 启用CORS支持
.csrf().disable() // 生产环境需谨慎
.authorizeRequests()
.antMatchers("/api/**").permitAll()
.anyRequest().authenticated();
}
@Bean
public CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8080"));
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
configuration.setAllowedHeaders(Arrays.asList("*"));
configuration.setAllowCredentials(true);
configuration.setMaxAge(3600L);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
前端跨域处理
1 Axios配置
// axios.js
import axios from 'axios'
const service = axios.create({
baseURL: '/api',
timeout: 15000,
withCredentials: true // 携带Cookie
})
// 请求拦截器
service.interceptors.request.use(
config => {
const token = localStorage.getItem('token')
if (token) {
config.headers.Authorization = `Bearer ${token}`
}
return config
},
error => {
return Promise.reject(error)
}
)
// 响应拦截器
service.interceptors.response.use(
response => {
return response.data
},
error => {
if (error.response) {
switch (error.response.status) {
case 401:
// 处理未授权
router.push('/login')
break
case 403:
// 处理禁止访问
break
default:
break
}
}
return Promise.reject(error)
}
)
export default service
2 Vue/React配置代理
Vue.config.js:
module.exports = {
devServer: {
proxy: {
'/api': {
target: 'http://localhost:9090', // 后端地址
changeOrigin: true, // 改变请求源
pathRewrite: {
'^/api': '' // 重写路径
}
}
}
}
}
常见问题处理
1 携带Cookie的跨域请求
// 后端配置
@Configuration
public class CorsConfig {
@Bean
public CorsFilter corsFilter() {
CorsConfiguration config = new CorsConfiguration();
// 注意:使用allowCredentials时,不能使用 "*" 作为origin
config.setAllowedOriginPatterns(Arrays.asList("http://localhost:8080"));
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
2 预检请求(OPTIONS)
@RestControllerAdvice
public class GlobalExceptionHandler {
@ExceptionHandler(Exception.class)
public Result handleException(Exception e) {
// 处理预检请求
if (e instanceof HttpRequestMethodNotSupportedException) {
return Result.error(405, "请求方式不支持");
}
return Result.error(500, e.getMessage());
}
}
最佳实践建议
- 生产环境:采用CORS过滤器方案,配合Spring Security
- 开发环境:使用代理转发,避免跨域问题
- 安全考虑:
- 不要使用通配符,指定具体域名
- 谨慎使用
allowCredentials(true) - 设置合理的预检请求缓存时间
- 性能优化:
- 减少预检请求次数
- 合理设置
maxAge - 使用HTTP缓存
测试跨域配置
# 使用curl测试跨域请求 curl -X OPTIONS http://localhost:8080/api/users \ -H "Origin: http://localhost:3000" \ -H "Access-Control-Request-Method: GET" \ -v # 检查响应头 # Access-Control-Allow-Origin: http://localhost:3000 # Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS # Access-Control-Allow-Headers: Authorization, Content-Type
通过以上方案,可以完整解决Java项目中的跨域问题,让前后端分离开发更加顺畅。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播