从 Ajax 调用 Spring Boot Rest API 时出现 CORS 错误

Posted

技术标签:

【中文标题】从 Ajax 调用 Spring Boot Rest API 时出现 CORS 错误【英文标题】:CORS error while calling Spring Boot Rest API from Ajax 【发布时间】:2019-07-05 18:55:24 【问题描述】:

我们在 ubuntu 服务器上运行 Spring Boot 应用程序。我们使用 Netflix Zuul 作为 API 网关,使用 Eureka 作为服务注册。并使用 Apache2 作为 DNS 的网络服务器。

当我通过 jQuery Ajax 从本地调用 API 时,出现以下异常:

Access to XMLHttpRequest at 'https://*****.com/api/users' from origin 'null' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

我可以在 Request Headers

下看到 "Origin: null"

Ajax 代码:

$.ajax( 
    type: "GET",
    dataType: "json",
    crossDomain: true,
    headers: 
        'Accept':'application/json',
        'Content-Type':'application/json',
        'Access-Control-Allow-Origin': "*"
    ,
    url: "https://*****.com/api/users",
    success: function(data)        
        //alert(data);
        console.log(data);
    
);

要修复 CORS,尝试了以下方法: 在 apache 中添加了所需的配置:

Header set Access-Control-Allow-Origin "*"
Header set Access-Control-Allow-Methods "POST, GET, OPTIONS, DELETE, PUT"
Header set Access-Control-Max-Age "1000"
Header set Access-Control-Allow-Headers "x-requested-with, Content-Type, origin, authorization, accept, client-security-token"

在 WebMvcConfigurerAdapter 实现类中添加 CorsMappings:

@Override
public void addCorsMappings(CorsRegistry registry) 
    registry.addMapping("/**").allowedOrigins("*").allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("*");

在 Zuul 代理类中添加了 CorsFilter bean(使用 @EnableZuulProxy 注释):

@Bean
public CorsFilter corsFilter() 
    final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
    final CorsConfiguration config = new CorsConfiguration();
    config.setAllowCredentials(true);
    config.addAllowedOrigin("*");
    config.addAllowedHeader("*");
    config.addAllowedMethod("OPTIONS");
    config.addAllowedMethod("HEAD");
    config.addAllowedMethod("GET");
    config.addAllowedMethod("PUT");
    config.addAllowedMethod("POST");
    config.addAllowedMethod("DELETE");
    config.addAllowedMethod("PATCH");
    source.registerCorsConfiguration("/**", config);
    return new CorsFilter(source);

但仍然是同样的错误。有什么想法可以解决这个问题吗? 谢谢。

【问题讨论】:

响应的 HTTP 状态码是什么?此外,在您的前端代码中,在您的 ajax 调用选项的“标头”部分中,删除 Access-Control-Allow-Origin 标头。 Access-Control-Allow-Origin 是响应标头,而不是请求标头。您不会通过尝试将其设置为请求标头来解决任何问题。 我已经尝试不使用原始标头,但它不起作用。 HTTP 响应:请求方法:OPTIONS 状态码:200 OK 【参考方案1】:

解决方案 1:

import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class CORSFilter implements Filter 

    /**
     * CORS filter for http-request and response
     */
    public CORSFilter() 
    

    /**
     * Do Filter on every http-request.
     */
    @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", "POST, PUT, GET, OPTIONS, DELETE");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "access_token, authorization, content-type");

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

    /**
     * Destroy method
     */
    @Override
    public void destroy() 
    

    /**
     * Initialize CORS filter
     */
    @Override
    public void init(FilterConfig arg0) throws ServletException 
    


解决方案 2:

@CrossOrigin
@GetMapping("/getAnyThing")
    public ResponseEntity<Object> getAnyThing() 
        return ResponseEntity.ok(service.getAnyThing());
    

这将解决您的端点

【讨论】:

我正在使用 Zuul API 网关。在 zuul 服务中添加了 CORSFilter。解决方案 1 不起作用。我在 api 方法级别添加了@CrossOrigin。但解决方案 2 也不起作用。【参考方案2】:

下面的完整课程对我很有帮助

@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", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        response.setHeader("Access-Control-Allow-Headers", "*");
        // response.setHeader("Access-Control-Expose-Headers","yourCustomHeaderIfExist");

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

    @Override
    public void init(FilterConfig filterConfig) 
    

    @Override
    public void destroy() 
    


【讨论】:

我正在使用 API 网关 Zuul。所以我在zuul服务中添加了上面的过滤器,但不起作用。得到同样的错误。 在这种情况下,可能存在三个潜在点。服务本身、Zuul 服务(网关)和 apache 服务器。我会为此尝试我的 zuul 网关,因为我记得我使用上述技术修复了它 啊,我刚刚注意到您将它放在 Zuul 服务上。不。您只需确保将此过滤器放在 End Api 服务本身上,我刚刚在 Zuul Gateway 服务存在时尝试过它,并且效果很好 你的意思是说我必须在用户服务中添加 CORSFilter 类而不是 Zuul 代理服务? 是的,我就是这个意思

以上是关于从 Ajax 调用 Spring Boot Rest API 时出现 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

对 Spring Boot 控制器的 Ajax 调用以重定向视图

Ajax 请求未调用 Spring Boot 控制器

Jquery Ajax 调用 + Spring boot 控制器 = 日期修改

无法从简单的 Ajax 函数调用 Spring Boot RestController 中的 GET 方法

Ajax 调用在 Spring Boot 中返回值为 JSONArray.fromObject(data) 时给出错误 500

在 Spring Boot Web Thymeleaf 应用程序中进行 AJAX 调用的正确方法是获取 getOutputStream() 已经为此响应调用