# 处理跨域

询问了 ds r1 怎么解决跨域,他给了我以下几个方法(只测试了第二种,其他的先懒得测了):

(从这里开始是 ds 说的)
在 Spring Boot 中处理跨域请求可以通过以下几种方法实现,以下是详细的配置步骤和示例:


# 方法一:使用 @CrossOrigin 注解(局部配置)

适用于对单个 Controller 或方法设置跨域规则。
步骤:

  1. 在 Controller 类或方法上添加 @CrossOrigin 注解
    可配置允许的来源、方法、头部等。

示例代码:

@RestController
@RequestMapping("/api")
@CrossOrigin(origins = "http://localhost:3000", 
             methods = {RequestMethod.GET, RequestMethod.POST},
             allowedHeaders = "*",
             allowCredentials = "true")
public class MyController {
    @GetMapping("/data")
    public ResponseEntity<String> getData() {
        // ... ... 
    }
}

参数说明:

  • origins : 允许的源列表(如 "http://example.com"
  • methods : 允许的 HTTP 方法(如 GET , POST
  • allowedHeaders : 允许的请求头(默认为所有)
  • allowCredentials : 是否允许携带凭证(如 Cookies)

# 方法二:全局配置(推荐)

通过实现 WebMvcConfigurer 接口统一配置跨域规则。
步骤:
2. 创建全局跨域配置类
使用 @Configuration 注解标记,并实现 WebMvcConfigurer

示例代码:

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")           // 匹配所有路径
                .allowedOrigins("http://localhost:3000") // 允许的源
                .allowedMethods("*")         // 允许所有 HTTP 方法
                .allowedHeaders("*")         // 允许所有请求头
                .allowCredentials(true)      // 允许携带凭证
                .maxAge(3600);               // 预检请求缓存时间(秒)
    }
}

# 方法三:结合 Spring Security 的跨域配置

如果项目使用了 Spring Security,需额外配置。
步骤:
3. 在 Security 配置中启用 CORS 并禁用 CSRF(如需携带凭证需开启)
4. 确保全局 CORS 配置生效

示例代码:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()                  // 启用 CORS 支持
            .csrf().disable()              // (可选)关闭 CSRF 保护
            .authorizeRequests()
            .anyRequest().authenticated();
    }
    // 若使用全局 CORS 配置,需显式声明 CorsConfigurationSource
    @Bean
    public CorsConfigurationSource corsConfigurationSource() {
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowedOrigins(Arrays.asList("http://localhost:3000"));
        config.setAllowedMethods(Arrays.asList("GET", "POST"));
        config.setAllowedHeaders(Arrays.asList("*"));
        config.setAllowCredentials(true);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", config);
        return source;
    }
}

# 方法四:使用 Filter 手动配置

指定一个 Filter 来设置响应头,灵活但需谨慎。
步骤:
5. 创建 CORS 过滤器并注册
手动设置响应头处理跨域。

示例代码:

@WebFilter("/*")
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", "http://localhost:3000");
        response.setHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "*");
        response.setHeader("Access-Control-Allow-Credentials", "true");
        response.setHeader("Access-Control-Max-Age", "3600");
        chain.doFilter(req, res);
    }
}

注册 Filter:

@Configuration
public class FilterConfig {
    
    @Bean
    public FilterRegistrationBean<CorsFilter> corsFilter() {
        FilterRegistrationBean<CorsFilter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CorsFilter());
        registration.addUrlPatterns("/*");
        return registration;
    }
}

# 常见问题解决

  1. 预检请求(OPTIONS)被拦截
    • 确保 Spring Security 放行 OPTIONS 方法:
      http.authorizeRequests().antMatchers(HttpMethod.OPTIONS).permitAll();
  2. allowCredentials=trueallowedOrigins 包含通配符 *
    • 需指定具体域名如 .allowedOrigins("http://localhost:3000")

# 最佳实践建议

  • 开发环境:允许所有来源( allowedOrigins("*") ),快速调试。
  • 生产环境:精确配置 allowedOrigins 以增强安全性。
  • 结合全局配置和 Spring Security:确保多层级安全控制。
  • 日志与测试:使用 Postman 或浏览器开发者工具验证响应头是否正确包含 CORS 信息。

按需选择配置方式,推荐使用 全局配置(方法二) 搭配 Spring Security(方法三),既统一管理,又兼顾安全性。
(ds 说的结束)


# 多路径放行

测试了第二个方法,发现 ds 给我的代码只能指定 ip 及端口号处理跨域。以前我 midway 直接配置一下就全都放行了。当然,指定路径肯定更安全。
尝试直接把放行路径改成 * ,出了问题,故问通义灵码,以下是回答:

从错误信息来看,问题出在 CORS(跨域资源共享)配置上。具体来说,当 allowCredentials 设置为 true 时, allowedOrigins 不能包含通配符 * ,因为这会导致 Access-Control-Allow-Origin 响应头无法正确设置。要解决这个问题,有两种方法:

  1. 显式列出允许的源:将具体的域名添加到 allowedOrigins 中。
  2. 使用 allowedOriginPatterns :这是 Spring 5.3 引入的新特性,允许你使用模式来匹配多个源。
    下面是具体的代码示例,展示了如何进行这两种配置:

# 方法一:显式列出允许的源

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("https://example.com", "https://another-example.com") // 显式列出允许的源
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true);
    }
}

# 方法二:使用 allowedOriginPatterns

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOriginPatterns("https://*.example.com", "https://*.another-example.com") // 使用模式匹配多个源
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowCredentials(true);
    }
}

# 解释

  • allowedOrigins :用于指定允许的源域名。如果需要支持多个域名,可以逐一列出。
  • allowedOriginPatterns :用于指定允许的源域名模式。这种方式更加灵活,适用于多个子域名或特定模式的域名。
  • allowCredentials(true) :允许凭证(如 Cookie、HTTP 认证信息等)随请求发送。
    选择其中一种方法进行配置即可解决问题。推荐使用 allowedOriginPatterns ,因为它更灵活且易于维护。

# 放行 localhost

又问了一下怎么可以放行全部 localhost,通义灵码给了回答:

如果你想要允许所有来自 localhost 的源,可以使用通配符 * 来匹配所有端口。但是需要注意的是,使用 * 允许所有源时, allowCredentials(true) 是不允许的,因为这会引发安全问题。
如果你确实需要允许所有 localhost 的源并且允许携带凭证,你需要明确指定每个可能的端口,或者在开发环境中暂时放宽限制。以下是两种方法:

  1. 指定所有可能的 localhost 端口

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("http://localhost:3000", "http://localhost:8080", "http://localhost:8081") // 添加所有可能的端口
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(3600);
    }
  2. 在开发环境中允许所有源(不推荐用于生产环境):

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedOrigins("*") // 允许所有源
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowCredentials(false) // 不允许携带凭证
                .maxAge(3600);
    }
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

北沐清 微信支付

微信支付

北沐清 支付宝

支付宝