You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

已添加@CrossOrigin仍遇CORS预检失败,求JS调用REST API解决方案

解决CORS预检失败问题

1. 先修正前端请求的错误配置

你前端请求里加的Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers这些头完全是多余的——这些是后端返回给浏览器的响应头,不是前端发给后端的请求头。前端带这些头会干扰浏览器的预检逻辑,直接删掉:

fetch("https://capgt-api.eng.us.devcare*w*re.net/tagament/v1/assignbadge", {
    method: "POST",
    mode: "cors",
    headers: {
      "Content-Type": "application/json",
      "Tenant-Short-Name": "DWXENG",
      "Authorization": "Bearer eyJhb....."
    },
    body: JSON.stringify(json),
  })

2. 优化后端@CrossOrigin注解的配置

默认的@CrossOrigin只允许简单头,而你的请求带了Authorization和自定义的Tenant-Short-Name,这些属于非简单头,需要明确指定允许的头、方法:

// 明确指定允许的Origin、方法、请求头
@CrossOrigin(origins = "*", // 建议替换为前端实际域名,比如"https://your-frontend.com"
             allowedHeaders = {"Content-Type", "Authorization", "Tenant-Short-Name", "Accept"},
             methods = {RequestMethod.POST, RequestMethod.OPTIONS})
@PostMapping(value = "/assignbadge", consumes = {MediaType.APPLICATION_JSON_VALUE}, produces = {MediaType.APPLICATION_JSON_VALUE})
public ResponseEntity<Object> assignBadge(@Parameter(description = "Badge Assignment Input", required = true) @RequestBody final AssitTag assitTag, @Context final HttpServletRequest request) throws IBusConnectionException {
    // 方法逻辑
}

3. 确保全局CORS过滤器的优先级

如果用了全局CORS过滤器,要让它成为第一个执行的过滤器,避免被其他拦截器(比如Spring Security)提前拦截OPTIONS请求。给过滤器加上最高优先级标记:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
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", "*");
        response.setHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE");
        response.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, Tenant-Short-Name, Accept");
        response.setHeader("Access-Control-Max-Age", "3600"); // 缓存预检结果,减少重复请求

        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    // 初始化、销毁方法可留空
}

4. 检查Spring Security(若使用)的配置

如果项目集成了Spring Security,它会默认拦截OPTIONS请求,需要在安全配置里明确放行OPTIONS请求:

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and()
            .authorizeRequests()
            .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 放行所有OPTIONS请求
            .anyRequest().authenticated();
        // 其他安全配置
    }
}

5. 验证预检请求响应

打开浏览器开发者工具(Network标签),查看OPTIONS请求的响应:

  • 确认响应头包含Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers,且值覆盖你的请求头和方法
  • 确认OPTIONS请求返回200状态码

Swagger和Postman能正常调用是因为它们不受浏览器同源策略限制,只有浏览器会触发预检请求,按上述步骤调整后即可解决问题。

内容的提问来源于stack exchange,提问作者ps suj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 00:00:27