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

Angular调用Spring Boot API遇CORS错误,预检请求未通过

问题描述

后端基于Spring Boot开发,运行在localhost:9090;前端基于Angular开发,运行在localhost:4200。调用后端接口时触发CORS错误:

从源地址'http://localhost:4200'访问'http://localhost:9090/vendor-data/'的XMLHttpRequest被CORS policy阻止:预检请求的响应未通过访问控制检查:不具备HTTP ok状态。

相关代码

前端代码

Service文件

getVendorData(headersData:any):Observable<any>{
  return this.http.get('http://localhost:9090/vendor-data/',{headers:headersData});
}

Component.ts文件

ngOnInit() {
    const token = localStorage.getItem('token');
    const headers = new HttpHeaders({
      Authorization: `Bearer ${token}`,
    });
    console.log(this.data.getVendorData(headers))
    this.data.getVendorData(headers).subscribe({
      next: (v) => {
        this.vendorList = v;
      },
      error: (e) => {},
      complete: () => { },
    });
  }

后端代码

CORS配置类

@Configuration
@EnableWebMvc
public class VendorConfiguration implements WebMvcConfigurer {

    public void addCorsMappings(CorsRegistry registry) {
         registry.addMapping("/**").allowedOrigins("http://localhost:4200")
         .allowedMethods("GET", "POST", "PUT", "DELETE")
             .allowCredentials(true);                                                                               
    }
}

JWT过滤器类

public class DataFilter extends OncePerRequestFilter{
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        
        String token=extractToken(request);
        boolean isError=true;
        
        if(token!=null && token.length()>6) {
            try {
                Jwts
                .parserBuilder()
                .setSigningKey(Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(
                        "f9b2b91e3c468f1937598573b00d923426127dc06bf6cc8b446fac9ec1364f88")))
                .build()
                .parseClaimsJws(token)
                .getBody();
                isError=false;
                filterChain.doFilter(request, response);
            }
            catch(SignatureException e) {
                System.out.print("Invalid Signature");
            }
            catch(MalformedJwtException e) {
                System.out.print("Invalid Token");
            }
        }
        if(isError) {
            (response).sendError(HttpStatus.UNAUTHORIZED.value(),"Unauthorized");
        }
    }

    private String extractToken(HttpServletRequest request) {
        String authHeader = request.getHeader("Authorization");
        String token = null;
        if (authHeader != null) {
            token = authHeader.substring(7);
        }
        return token;
    }
}

已尝试在Controller类添加@CrossOrigin("*")注解,问题依旧。疑问:是否是过滤器类导致了该错误?


问题原因及解决方案

是的,这个JWT过滤器就是导致CORS预检失败的核心原因。

浏览器发送的CORS预检请求(OPTIONS方法)不会携带Authorization头,但你的过滤器会直接执行token校验逻辑,发现没有有效token后返回401 Unauthorized状态码。而CORS预检请求要求响应必须返回200 OK或其他允许的状态码,因此触发了CORS错误。

具体解决方案

  1. 让过滤器跳过OPTIONS预检请求
    修改过滤器的doFilterInternal方法,先判断请求方法是否为OPTIONS,若是则直接放行,不执行token校验:
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
        throws ServletException, IOException {
    
    // 跳过OPTIONS预检请求,直接放行
    if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
        filterChain.doFilter(request, response);
        return;
    }

    String token=extractToken(request);
    boolean isError=true;
    
    if(token!=null && token.length()>6) {
        try {
            Jwts
            .parserBuilder()
            .setSigningKey(Keys.hmacShaKeyFor(Decoders.BASE64URL.decode(
                    "f9b2b91e3c468f1937598573b00d923426127dc06bf6cc8b446fac9ec1364f88")))
            .build()
            .parseClaimsJws(token)
            .getBody();
            isError=false;
            filterChain.doFilter(request, response);
        }
        catch(SignatureException e) {
            System.out.print("Invalid Signature");
        }
        catch(MalformedJwtException e) {
            System.out.print("Invalid Token");
        }
    }
    if(isError) {
        response.sendError(HttpStatus.UNAUTHORIZED.value(),"Unauthorized");
    }
}
  1. 完善CORS配置
    在CORS配置中显式允许Authorization头和OPTIONS方法,确保预检请求能正确识别允许的自定义头:
public void addCorsMappings(CorsRegistry registry) {
     registry.addMapping("/**")
             .allowedOrigins("http://localhost:4200")
             .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
             .allowedHeaders("Authorization", "Content-Type")
             .allowCredentials(true);                                                                               
}

额外注意事项

  • 确保过滤器的注册顺序正确,CORS相关处理需优先于JWT过滤器执行(Spring Boot默认CORS配置会在过滤器前处理,但跳过OPTIONS请求是最直接的解决方式)。
  • 后续需检查前端token的有效性,避免因token无效导致的401错误,但当前CORS问题的根源已解决。

内容的提问来源于stack exchange,提问作者Arnab Das

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 12:18:11