其实就是跨域请求。我们知道XHR只能访问同一个域中的资源,这是浏览器的安全策略所限制,但是开发中合理的跨域请求是必须的。CORS是W3的一个工作草案,基本思想就是:使用自定义的HTTP头部让浏览器与服务器沟通,决定响应成功或失败。
CORS需要浏览器和服务器同时支持,所有浏览器都支持该功能,IE浏览器在IE10以上支持。
CORS跟同源AJAX请求差别不大,主要是浏览器发现Ajax跨域请求时候,自动添加一些附加的头部信息,有时多一次附加的OPTIONS预检查请求,但用户不会感知。
(闲话:实际项目中经常遇到Access-Control-Allow-Origin报错,network里面请求数据时候会多请求一次methods为options方法的请求,它返回200后才真正再去请求一次真正的接口请求,这都是请求跨域时候的表现)
Important Part:CORS将请求分成两大类,simple request(简单请求)和not-so-simple request(非简单请求)
简单请求的请求方法是:HEAD GET POST其中之一
头部信息不超过下面几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:application/x-www-form-urlencoded,multipart/form-data,text/plain
不是简单请求的就是复杂请求了。
浏览器处理简单请求步骤:
直接发起CORS请求,在request header里面添加origin字段源Url(协议+域名+端口号),如果不在许可范围内部,服务器也是返回正常的HTTP response,但是response header里面没有包含Access-Control-Allow-Origin字段,console控制台报错,被浏览器的XHR对象的onerror回调捕获,此时的HTTP返回码可能是200。
Origin: http://www.nczonline.net
服务器认为该请求可以接受,response Header里面就会返回Access-Control-Allow-Origin返回相同的源信息地址。
Access-Control-Allow-Origin: http://www.nczonline.net
Access-Control-Allow-Credentials:true //是否允许发送Cookie
Access-Control-Expost-Headers:FooBar //获取request header里面额外的字段值
Content-Type:text/html;charset=utf-8
如果没有origin信息或者信息不匹配,那么浏览器就驳回请求,浏览器的请求和响应都不包含cookie信息。
Question:为什么CORS跨域请求和响应默认不包含cookie信息?
Answer:cookie是同源共享的,既然你都跨域了,就不能使用不同域的cookie信息了。
—————————————————————————————————————
Preflighted Requests(预检请求):
比如非简单请求:PUT,DELETE或者Content-Type是application/json类型的请求。在正式请求之前增加一次HTTP查询请求,称为”预检请求“。
OPTIONS /cors HTTP/1.1 Origin: http://api.bob.com Access-Control-Request-Method: PUT Access-Control-Request-Headers: X-Custom-Header Host: api.alice.com Accept-Language: en-US Connection: keep-alive User-Agent: Mozilla/5.0...
上面是预检请求的HTTP requset Header参数,可以看出请求方法是OPTIONS,关键字Origin请求来自哪个源地址,Access-Control-Request-Method:请求方法,Access-Control-Request-Headers:逗号分隔的字符串,浏览器额外附加的头部信息。
服务器收到预检请求后,检查origin,Access-Control-Request-Method和Access-Control-Request-Headers字段后,确认可以跨域,就返回:
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
Access-Control-Allow-Origin可以设为*,表示同意任意跨源请求。
__________________________________________________________________
一旦服务器通过了预检请求,以后每次的正常CORS请求,跟简单请求一样,有Origin头部信息字段,服务器的response header里面会有
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 01:15:39 GMT Server: Apache/2.0.61 (Unix) Access-Control-Allow-Origin: http://api.bob.com Access-Control-Allow-Methods: GET, POST, PUT Access-Control-Allow-Headers: X-Custom-Header Content-Type: text/html; charset=utf-8 Content-Encoding: gzip Content-Length: 0 Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Content-Type: text/plain
头部信息字段。
如果是非简单请求的话,预检之后的response header里面必包含Access-Control-Allow-Origin头部信息。
————————————————————————————————————
CORS会通过预请求的透明服务器验证(透明是指封闭不可见的)机制支持开发者使用自定义头部,GET或POST之外的方法,不同类型的主体内容,预检请求发送的是OPTIONS方法,头部信息包含:
Origin
Access-Control-Request-Method
Access-Control-Request-Headers
发送请求后,OPTIONS预检请求结束,再次进行真正的Response响应请求。
跨域请求默认是不带凭证:cookie,HTTP认证和SSL证明的。但是可以通过设置:withCredentials属性为true,指定某个请求应该发送凭证,然后服务器接受请求后,Response Header里面会返回:
Access-Control-Allow-Credentials:true
各个浏览器对CORS的支持程度不同,但是都支持简单请求,可以通过检查是否存在withCredentials属性,IE的XDR跟XHR类似,实现安全可靠的跨域通信。所以可以先检测withCredentials属性,再检测XDR对象是否存在,就可以兼顾所有浏览器了。
其他跨域技术:
图像Ping:利用img标签的src属性,进行GET请求访问,不能得到服务器的返回。适合单向通信。
JSONP:利用script标签的src属性,动态生成js脚本,执行服务器返回的js脚本中的带有JSON参数的回调函数。可以通过拿到响应参数自执行回调函数,简单有用。
——————————————————————————————————————————
CORS和JSONP使用目的相同,但是比JSONP更加强大,CORS主要是服务端配置好后,浏览器根据服务端配置的自定义头部和提供的可以进行的CORS的方法来进行跨域操作
JSONP只支持GET请求,CORS支持所有类型的HTTP请求。
【完】
时光荏苒,如白驹过隙。
岁月如斯,然赤心如故。