1.何为CORS?
CORS全称为Cross-Origin Resource Sharing,跨源资源共享(俗称跨域资源共享)。
照搬HTTP文档对CORS的定义:CORS是一种机制,该机制使用附加的HTTP header来告诉浏览器,准许运行在一个源上的Web应用访问位于另一不同源选定的资源。 当一个Web应用发起一个与自身所在源(域,协议和端口)不同的HTTP请求时,它发起的即跨源HTTP请求。
如果觉得中文绕口,可以看英文:Cross-Origin Resource Sharing (CORS) is a mechanism that uses additional HTTP headers to tell browsers to give a web application running at one origin, access to selected resources from a different origin. A web application executes a cross-origin HTTP request when it requests a resource that has a different origin (domain, protocol, or port) from its own.
不理解没关系,接着往下看,后面会再做解读。
首先,举个两个例子来方便理解何为跨源:
1.用户直接访问百度,这不叫跨源。因为请求来自用户的浏览器,而不是某个服务器(源)。
2.用户访问A.com,按下页面上的某个按钮后,A网站上的ajax代码运行,希望访问B.com上的资源,从而对自己的页面进行动态加载。这时,A源希望访问B源,那么这种行为就是跨源。事实上,只要域名、协议、端口有任一不同,都算跨源。
出于安全性,浏览器限制例2这种脚本内发起的跨源HTTP请求。 ajax遵循同源策略(same-origin policy), 这意味着使用ajax的Web应用程序只能从加载应用程序的同一个域请求HTTP资源,除非响应报文包含了正确CORS响应头。
一般来说,最常见的跨域情景,是ajax跨域,还有网站加载第三方字体的时候。工作中遇到的需要跨域的情况,大多数都是使用ajax的时候。
2.CORS的运作原理
如何进行跨域访问呢?在CORS出来以前,有使用flash插件发送请求,以绕开浏览器限制的;还有使用代理服务器转发的。而到了HTML5以后,新的跨域策略诞生了:CORS
使用CORS后的跨域访问过程,其实一句话就可以概括:A想访问B的资源,按照同源策略,为了保护B,这是不允许的。但如果B本身允许A访问呢?那B就告诉浏览器:我允许A跨域访问我!于是A就可以开开心心的访问B了。
上述过程,是通过在请求和响应的http中,添加特定的http header,来完成的。接下来详细屡一下流程。
首先,用户正在使用A.com提供的web应用程序,此时用户的某个操作触发了A.com的ajax脚本,于是该脚本对B.com发送了请求。由于是跨源请求,A在http请求头中添加了一行Origin字段:
GET /resources/public-data/ HTTP/1.1 Host: B.com User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10.5; en-US; rv:1.9.1b3pre) Gecko/20081130 Minefield/3.1b3pre Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Language: en-us,en;q=0.5 Accept-Encoding: gzip,deflate Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 Connection: keep-alive Origin: http://A.com
当B服务器接收到该请求后,看到请求头中有Origin字段,明白了这是CORS跨域请求。此时,B服务器会按正常行为处理该请求,正常返回response。但是,在响应头中,会添加这么一行字段:
HTTP/1.1 200 OK Date: Mon, 01 Dec 2008 00:23:53 GMT Server: Apache/2.0.61 Access-Control-Allow-Origin: * Keep-Alive: timeout=2, max=100 Connection: Keep-Alive Transfer-Encoding: chunked Content-Type: application/xml
当浏览器接收到该响应后,它会查看响应头中的Access-Control-Allow-Origin字段是否包含本域(A.com),如果包含,则将该响应交给发出该ajax请求的js脚本。星号表示全匹配。
以上就是最简单的一次CORS跨域请求,这其中有两点需要注意:
1.想要跨域访问,决定权掌握在对方手中,看且只看对方同不同意(此例中的B服务器)。
2.是浏览器来判断该响应能否交给js,而不是对方服务器。换句话说就是,服务器是永远都会返回正常响应的,而这个响应最终能不能到你手上(能否跨域成功),是浏览器在做决定。
此时再回头看看CORS的定义,就能明白,CORS机制,就是通过在http头部添加一些信息,让浏览器准许一个源获取另一个源的资源。浏览器才是大哥,是这次跨域通信的交通警察。
如果跨域失败,直接按F12的话,是可以看到服务器的响应的。而如果让js打印出response,则毛都打印不出来。因为浏览器代表用户,而js代表源(比如A站的站长),用户看到response是没事的,就像用户正常访问百度一样,这不是跨域。但js如果不经同意就看到了B站发来的response,那背后的程序员(A站站长)可能会干坏事,这是不允许的。
3.更复杂的CORS使用场景(带凭证)
HTTP文档提供了3类CORS的使用场景。上面的例子属于简单请求(Simple requests),还有预检请求(Preflighted requests)和带凭证请求(Requests with credentials)。具体的内容见文档(后面会给出链接),这里只针对带凭证请求,具体的讲一下怎么做(原理请看文档),毕竟需要操作cookie的情景还是很常见的。
withCredentials = true。
Access-Control-Expose-Headers: ‘Set-Cookie‘
这代表服务器允许其他源获取Set-Cookie头部字段,此时浏览器才会把该信息安心地交给脚本。
如果上述4条都无法解决问题,建议了解cookie的domain原则和第三方cookie。有时间的话会继续更。
参考资料:
1.https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS
2.https://www.liaoxuefeng.com/wiki/1022910821149312/1023022332902400
3.https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Cookies
原文:https://www.cnblogs.com/ShiveryMoon/p/13733051.html