XHR cross error 跨域问题解决

一 问题

   后端的API,直接通过IP+端口访问没问题,直接访问域名也OK。通过别的域名跨域访问就异常了。

console也明确提示:

 二 修改

以下为springboot bean注入方式。  

  新增拦截器代码,

public class CORSFilter extends GenericFilterBean implements Filter {

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chaine)
            throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.setHeader("Access-Control-Allow-Origin", "www.a.com");
        httpResponse.setHeader("Access-Control-Allow-Methods", "PUT, POST, GET, OPTIONS, DELETE");
        httpResponse.setHeader("Access-Control-Allow-Headers", "content-type, authorization");
        httpResponse.setHeader("Access-Control-Allow-Credentials", "true");
        httpResponse.setHeader("Access-Control-Max-Age", "3600");
        System.out.println("****************** CORS Configuration Completed *******************");
        HttpServletRequest httpServletRequest = (HttpServletRequest) request;
        if (httpServletRequest.getMethod().equals("OPTIONS"))
            httpResponse.setStatus(HttpServletResponse.SC_OK);
        chaine.doFilter(request, response);
    }

}

再原来的拦截器配置增加:注意setorder 数字越小优先级越高。这个放在@Configuration 类里面。

    @Bean
    public FilterRegistrationBean crossFilter() {
        FilterRegistrationBean registrationBean = new FilterRegistrationBean(new CORSFilter());
        ArrayList<String> urls = new ArrayList<>();
        urls.add("/*");//配置过滤规则
        registrationBean.setUrlPatterns(urls);
        registrationBean.setOrder(1);
        logger.info("cross filer over");
        return registrationBean;
    }

NG配置:

location / {  
    add_header Access-Control-Allow-Origin *;
    add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
    add_header Access-Control-Allow-Headers 'DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';

    if ($request_method = 'OPTIONS') {
        return 204;
    }
} 

一定要注意OPTIONS配置。

我们之前报错,就是NG先给拦住了,校验非正常请求直接403.

注意:

前端同学也得配合检查下请求方式:

$.ajax({
    url: "https://b.com/method",
    type: 'POST',
    data: requestParams,
    dataType: 'json',
    xhrFields: {
        withCredentials: true
    },
    crossDomain: true,
    async: false,
    ...

容易出问题的地方,url 只写path,不写明HTTP协议。参数不加上跨域请求。 

三 原理

 通常问题就会解决,这个问题折腾了大半天。看了下Mozilla浏览器对此的官方解释:

前端Web中有两个域名,a.com和b.com,其中a.com是访问主站(页面),b.com是数据提交接口的服务器(XHR请求)

普通的GET请求:

但是跨域的POST请求,就多了一步

这里涉及预检请求(preflight request)

跨域资源共享(CORS)标准新增了一组 HTTP 首部字段,允许服务器声明哪些源站有权限访问哪些资源。另外,规范要求,对那些可能对服务器数据产生副作用的HTTP 请求方法(特别是 GET 以外的 HTTP 请求,或者搭配某些 MIME 类型的 POST 请求),浏览器必须首先使用 OPTIONS 方法发起一个预检请求(preflight request),从而获知服务端是否允许该跨域请求。服务器确认允许之后,才发起实际的 HTTP 请求。在预检请求的返回中,服务器端也可以通知客户端,是否需要携带身份凭证(包括 Cookies 和 HTTP 认证相关数据)

Preflighted requests

Unlike “simple requests” (discussed above), for "preflighted" requests the browser first sends an HTTP request using the OPTIONS method to the resource on the other origin, in order to determine if the actual request is safe to send. Cross-site requests are preflighted like this since they may have implications to user data.

CORS规定,Content-Type不属于以下MIME类型的,都属于预检请求。所以 application/json的请求 会在正式通信之前,增加一次"预检"请求,会带上头部信息。

The Access-Control-Request-Method header notifies the server as part of a preflight request that when the actual request is sent, it will be sent with a POST request method. The Access-Control-Request-Headers header notifies the server that when the actual request is sent, it will be sent with a X-PINGOTHER and Content-Type custom headers. The server now has an opportunity to determine whether it wishes to accept a request under these circumstances.

Lines 13 - 22 above are the response that the server sends back, which indicate that the request method (POST) and request headers (X-PINGOTHER) are acceptable. In particular, let's look at lines 16-19:

Access-Control-Allow-Origin: http://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400

The server responds with Access-Control-Allow-Origin: http://foo.example, restricting access to just the requesting origin domain. It also responds with Access-Control-Allow-Methods, which says that POST and GET are viable methods to query the resource in question (this header is similar to the Allow response header, but used strictly within the context of access control).

The server also sends Access-Control-Allow-Headers with a value of "X-PINGOTHER, Content-Type", confirming that these are permitted headers to be used with the actual request. Like Access-Control-Allow-MethodsAccess-Control-Allow-Headers is a comma separated list of acceptable headers.

The server 响应信息,头部 也得包含允许的Access-Control-Allow-Origin, 我测试的时候传”*“不行,得加具体的domain.就是a.com.

还有Access-Control-Allow-Headers 等,具体见上面代码,表示接受非默认的的Content-Type。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

bohu83

买个馒头吃

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值