has been blocked by CORS policy: Response to preflight request doesn‘t pass access control check

has been blocked by CORS policy: Response to preflight request doesn't pass access control check

这个错误是添加完CorsFilter之后发生的错误,咋一看好像CorsFilter没有生效,其实CorsFilter生效了,而且通过log可以看出postman调用只调用一次,谷歌浏览器调用会调用两次,原因是谷歌浏览器在有跨域(CORS)请求时,会先发送一个preflight(预检)请求,之后才会发送fetch请求。

CORS:跨源资源共享 (CORS)(或通俗地译为跨域资源共享)是一种基于 HTTP 头的机制,该机制通过允许服务器标示除了它自己以外的其它origin(域,协议和端口),这样浏览器可以访问加载这些资源。跨源资源共享还通过一种机制来检查服务器是否会允许要发送的真实请求,该机制通过浏览器发起一个到服务器托管的跨源资源的"预检"请求。在预检中,浏览器发送的头中标示有HTTP方法和真实请求中会用到的头。

跨源HTTP请求的一个例子:运行在 https://domain-a.com 的 JavaScript 代码使用 XMLHttpRequest 来发起一个到 https://domain-b.com/data.json 的请求。

出于安全性,浏览器限制脚本内发起的跨源HTTP请求。 例如,XMLHttpRequest 和 Fetch API 遵循同源策略。这意味着使用这些 API 的 Web 应用程序只能从加载应用程序的同一个域请求 HTTP 资源,除非响应报文包含了正确 CORS 响应头。

问题:虽然前端只调用了一次接口,但是浏览器会发送两次请求,第一次是preflight请求,之所以会发这个请求是为了保证当前调用接口的有效性,避免资源浪费,确保有效链接。服务端在处理接口的时候直接按照客户端的fetch请求处理,并没有对preflight请求处理,返回了前端400。

解决办法:服务端对preflight请求和fetch请求做不同处理,两个请求不能走同一套逻辑,因为preflight请求不会携带request参数过去,只有fetch请求才会携带request。即在CorsFilter中增加代码:

        HttpServletRequest request = (HttpServletRequest)req;
        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return;
        }

前端啥也不用干,不用加什么xhrFields.withCredentials:true!,后端也不需要加什么Access-Control-Allow-Credentials", "true"

完整的代码:

@ServletComponentScan(basePackages={"com.xxx.base","com.xxx.open"})
@SpringBootApplication(scanBasePackages={"com.xxx.base","com.xxx.open"})
public class App {
	public static void main(String[] args) throws Exception {
		SpringApplication.run(App.class, args);
	}
}
import com.xxx.base.util.Utils;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebFilter(urlPatterns = "/*", filterName = "CorsFilter")
public class CorsFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
    }
    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
            throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        System.out.println(">>>>>>>>>>>>>>>>>来了》》》》》》》》》》》》》》》》"+request.getHeader("Origin"));
        if(Utils.isEmptyTrim(request.getHeader("Origin"))){
            response.setHeader("Access-Control-Allow-Origin", "*");
        }else{
            response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
        }
//        response.setHeader("Access-Control-Allow-Headers", "access-control-allow-origin, authority, content-type, version-info, X-Requested-With");
        response.setHeader("Access-Control-Allow-Headers", "*");
//        response.setHeader("Access-Control-Expose-Headers", "*");
        response.setHeader("Access-Control-Allow-Methods", "*");
        response.setHeader("Access-Control-Max-Age", "3600");
        //response.setHeader("Access-Control-Allow-Credentials", "true");
        if ("OPTIONS".equals(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
            return;
        }
        chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }
}

参考原文:https://blog.csdn.net/weixin_53512283/article/details/123923734

你可能感兴趣的:(JavaEE,java,前端,服务器)