Java后端跨域问题解决办法

本文详细介绍了跨域问题的产生原因、浏览器的同源策略以及三种常见的解决方法:基于过滤器的方式、使用SpringMVC的@CrossOrigin注解和SpringSecurity的自动配置。同时,还展示了如何在Nginx中处理跨域请求。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、跨域问题出现的原因

        跨域是指a页面想获取b页面资源,如果a、b页面的协议、域名、端口、子域名不同,或是a页面为ip地址,b页面为域名地址,所进行的访问行动都是跨域的,而浏览器为了安全问题一般都限制了跨域访问,也就是不允许跨域请求资源。

  跨域问题的根本原因:因为浏览器收到同源策略的限制,当前域名的js只能读取同域下的窗口属性。什么叫做同源策略?同源策略是浏览器的一个安全限制,要求域名、协议、端口相同,如果不同则没办法进行数据交互。而跨域配置,则是为了解除这方面的限制。

配置选项简介

  • Access-Control-Allow-Origin: 允许访问的域名
  • Access-Control-Allow-Methods: 允许访问的请求方式
  • Access-Control-Allow-Headers: 允许使用的 Header
  • Access-Control-Allow-Credentials: 是否允许用户发送、处理 Cookie
  • Access-Control-Max-Age: 预检有效期,单位为秒。有效期内,不需要重复发送预检请求
  • Access-Control-Expose-Headers: Header 白名单,不设置的话,客户端读不到 Header 的内容

二、解决办法

第一方法:

import org.springframework.context.annotation.Configuration;
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@WebFilter(filterName = "CorsFilter ")
@Configuration
public class CorsFilter implements Filter {
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        response.setHeader("Access-Control-Allow-Origin","*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, PATCH, DELETE, PUT");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
        chain.doFilter(req, res);
    }
}

        这种办法,是基于过滤器的方式,方式简单明了,这种办法,是基于过滤器的方式,方式简单明了,就是把这些响应头写入到response响应中去

第二种方法:

public class GoodsController {

    @CrossOrigin(origins = "http://localhost:4000")
    @GetMapping("goods-url")
    public Response queryGoodsWithGoodsUrl(@RequestParam String goodsUrl) throws Exception      {
    
    }
}  

        这种方法就是采用@CrossOrigin注解,查看@CrossOrigin源码,就能知道这注解可以放到method、class等上面,类似于@RequestMapping,也就是说这个这个注解可以控制class类中的所有方法跨域,也可以让单个方法进行跨域。这种方式虽然实现比较简单,但此方法只能实现局部跨域,当一个项目中存在多个类或者方法的话,使用这种方法比较麻烦,需要给所有类或者方法都添加上此注解。

第三种方法:

@Configuration
public class CrossDomainStarter {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        //放行的域名
        config.addAllowedOrigin("*");
        //放行的请求类型,有 GET, POST, PUT, DELETE, OPTIONS
        config.addAllowedMethod("*");
        //放行的请求头
        config.addAllowedHeader("*");
        //暴露头部信息
        config.addExposedHeader("*");
        //是否允许发送 Cookie
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**",config);

        return new CorsFilter(corsConfigurationSource);
    }
}

        而 Spring-Framework 5.3 版本之后,关于 CORS 跨域配置类 CorsConfiguration 中将 addAllowedOrigin 方法名修改为 addAllowedOriginPattern,因此配置了变成了以下这样:

@Configuration
public class CrossDomainStarter {

    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        //放行的域名
        config.addAllowedOriginPattern("*");
        //放行的请求类型,有 GET, POST, PUT, DELETE, OPTIONS
        config.addAllowedMethod("*");
        //放行的请求头
        config.addAllowedHeader("*");
        //暴露头部信息
        config.addExposedHeader("*");
        //是否允许发送 Cookie
        config.setAllowCredentials(true);

        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/**",config);

        return new CorsFilter(corsConfigurationSource);
    }
}

区别:

  1. addAllowedOriginPattern:这个方法允许通过使用通配符模式来匹配多个来源。您可以使用正则表达式或简单的通配符模式来指定允许的来源。例如,您可以使用addAllowedOriginPattern("*")来允许所有来源的访问,或使用addAllowedOriginPattern("https://*.example.com")来允许以"https://"开头并以".example.com"结尾的任何来源访问。这种方式更加灵活,可以满足多种来源的需求。
  2. addAllowedOrigin:这个方法用于指定允许访问资源的具体来源。您需要明确指定每个允许的来源。例如,您可以使用addAllowedOrigin("https://example.com")来允许只有"http://example.com"这个来源访问资源。这种方式更加具体和明确

Spring Security CORS 处理
        Spring Boot 环境下如果引入了 Spring Security,Spring 将自动配置 CorsFilter,此时从CorsConfigurationSource 类型的 bean 中读取 CORS 配置,因此将 CorsConfigurationSource 配置为 bean 即可。示例代码如下。

@Configuration
public class WebMvcConfig {

    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.addAllowedOrigin("*");
        corsConfiguration.addAllowedMethod("*");
        corsConfiguration.addAllowedHeader("*");
        corsConfiguration.setExposedHeaders(Arrays.asList("header1", "header2"));
        corsConfiguration.setMaxAge(3600L);
        corsConfiguration.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource corsConfigurationSource = new UrlBasedCorsConfigurationSource();
        corsConfigurationSource.registerCorsConfiguration("/*", corsConfiguration);
        return corsConfigurationSource;
    }
}

Nginx 跨域处理

在Nginx服务器的配置文件中添加以下代码:

server {
    listen       80;
    server_name  your_domain.com;
    location /api {
        # 允许跨域请求的域名,* 表示允许所有域名访问
        add_header 'Access-Control-Allow-Origin' '*';

        # 允许跨域请求的方法
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';

        # 允许跨域请求的自定义 Header
        add_header 'Access-Control-Allow-Headers' 'Origin, X-Requested-With, Content-Type, Accept';

        # 允许跨域请求的 Credential
        add_header 'Access-Control-Allow-Credentials' 'true';

        # 预检请求的存活时间,即 Options 请求的响应缓存时间
        add_header 'Access-Control-Max-Age' 3600;

        # 处理预检请求
        if ($request_method = 'OPTIONS') {
            return 204;
        }
    }
    # 其他配置...
}

上述示例中,location /api 代表配置针对 /api 路径的请求进行跨域设置

小结

跨域问题可以在网关层、反向代理层或应用层来解决,而它们的使用优先级是:网关层 > 代理层 > 应用层。因为越靠前覆盖范围就越大,解决跨域问题就越容易

### JAVA后端问题解决方案 #### 方法一:实现 `WebMvcConfigurer` 接口 可以通过自定义配置类并实现 `WebMvcConfigurer` 接口的方式,在全局范围内设置允许请求参数。这种方式适用于大多数场景下的需求。 ```java @Configuration public class WebConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 允许所有的接口路径被访问 .allowedOrigins("http://localhost:3000") // 设置允许的前端名 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法 .allowedHeaders("*") // 允许的头部信息 .allowCredentials(true); // 是否支持携带Cookie } } ``` 这种方法简单易用,适合中小型项目的快速部署[^1]。 --- #### 方法二:使用 `@CrossOrigin` 注解 对于特定的控制器或方法,可以直接在其上添加 `@CrossOrigin` 注解来指定允许规则。此方式灵活性较高,可以针对单个接口进行细粒度控制。 ```java @RestController @RequestMapping("/api") @CrossOrigin(origins = "http://localhost:3000", allowCredentials = "true", allowedHeaders = "*") public class ExampleController { @GetMapping("/data") public String getData() { return "This is cross-origin data"; } } ``` 该方案特别适合于某些特殊接口需要独立处理的情况[^2]。 --- #### 方法三:通过拦截器 (`HandlerInterceptor`) 实现 利用拦截器可以在请求到达具体业务逻辑之前对其进行预处理,从而动态地调整响应头中的相关内容。 ```java @Component public class CorsInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); if ("OPTIONS".equalsIgnoreCase(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); return false; } return true; } } ``` 这种做法能够更灵活地应对复杂的场景,尤其是在需要根据不同条件动态修改响应头的情况下非常有用[^3]。 --- #### 方法四:使用过滤器 (Filter) 创建一个基于 Servlet 的过滤器,统一为所有请求添加必要的响应头。 ```java @Component public class CorsFilter implements Filter { @Override public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) res; HttpServletRequest request = (HttpServletRequest) req; response.setHeader("Access-Control-Allow-Origin", "http://localhost:3000"); response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS"); response.setHeader("Access-Control-Max-Age", "3600"); response.setHeader("Access-Control-Allow-Headers", "*"); response.setHeader("Access-Control-Allow-Credentials", "true"); if ("OPTIONS".equals(request.getMethod())) { response.setStatus(HttpServletResponse.SC_OK); } else { chain.doFilter(req, res); } } } ``` 相比其他方式,过滤器的优势在于它可以完全脱离框架而工作,因此更加通用和稳定[^4]。 --- #### 方法五:Spring Security 中启用 CORS 支持 如果项目中集成了 Spring Security,则需要显式开启对 CORS 请求的支持,否则即使设置了规则也可能无法正常生效。 ```java @Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.cors().and() .csrf().disable(); } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Collections.singletonList("http://localhost:3000")); configuration.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } } ``` 这是生产环境中推荐的做法之一,因为它能更好地与其他安全性功能协同运作[^4]。 --- #### 总结 每种方法都有其适用范围和优缺点,实际应用时应根据具体的项目架构和技术栈选择最合适的方案。例如,小型项目可以选择简单的注解形式;而对于大型复杂系统则可能更适合采用集中式的配置管理手段如过滤器或者集成到安全框架之中。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值