技术分享 Technology to share

前端也要玩跨域“CORS”

说起CORS又是一个老生常谈的问题,这段时间在跟物联网对接,走的也是http服务、索性简单的请求就直接前端来发送(因为最终是在局域网里面所以不担心接口暴露,有权限才可以调用等问题,于是又见到我的老朋友了 cors


参考资料:

跨域资源共享 CORS 详解 -阮一峰

HTTP访问控制(CORS)

awesome-bookmarks


浏览器将CORS请求分成两类:简单请求simple request)和非简单请求not-so-simple request)。


只要同时满足以下两大条件,就属于简单请求。


请求方法是以下三种方法之一:

HEAD
GET
POST


HTTP的头信息不超出以下几种字段:

Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain


凡是不同时满足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不一样的。


简单请求可以在服务端设置响应头 Access-Control-Allow-Origin * 即可解决 常见报错如下图


但是你也会碰到如下所示的报错,这时候就属于非简单请求



非简单请求在设置响应头 Access-Control-Allow-Origin 时候就需要注意了 这里得*号 得换成指定的想要跨域的域名才行 例如:

//php code
header(Access-Control-Allow-Origin:www.hiwebpage.com)


非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。


withCredentials 属性

var xhr = new XMLHttpRequest(); 
xhr.withCredentials = true; //开启withCredentials 属性也是属于非简单请求 
//根据session实现的验证码这里也需要注意  这里为true 浏览器才会携带cookie 发送到服务器


服务段设置这个字段来接收浏览器传过来的cookie

Access-Control-Allow-Credentials: true



而且还要注意一点,也不是只有XMLHttpRequest或者 fetch请求才会有跨域问题,使用 drawImage 的 canvas、web 字体 、CSSDOM 也都是有这问题的。