前后端交互时经常受跨域问题的煎熬。最近正好遇到,所以略微总结了下,仅供参考!
什么是跨域
出于安全考虑,浏览器会限制脚本中发起的跨域请求,使用 XMLHttpRequest 对象和Fetch发起 HTTP 请求就必须遵守同源策略。即:“URL的首部”指window.location.protocol +window.location.host必须相同,也可以理解为“Domains, protocols and ports must match”。
跨源资源共享标准通过新增一系列 HTTP 头,让服务器能声明哪些来源可以通过浏览器访问该服务器上的资源。另外,对那些会对服务器数据造成破坏性影响的 HTTP 请求方法(特别是 GET 以外的 HTTP 方法,或者搭配某些MIME类型的POST请求),标准强烈要求浏览器必须先以 OPTIONS 请求方式发送一个预请求(preflight request),从而获知服务器端对跨源请求所支持 HTTP 方法。在确认服务器允许该跨源请求的情况下,以实际的 HTTP 请求方法发送那个真正的请求。服务器端也可以通知客户端,是不是需要随同请求一起发送信用信息(包括 Cookies 和 HTTP 认证相关数据)。
XMLHttpRequest 对象
XMLHttpRequest 对象用于在后台与服务器交换数据。开发者可通过XMLHttpRequest对象
* 在不重新加载页面的情况下更新网页
* 在页面已加载后从服务器请求数据
* 在页面已加载后从服务器接收数据
* 在后台向服务器发送数据
访问控制场景
简单请求
所谓的简单,是指:
- 只使用 GET, HEAD 或者 POST 请求方法。如果使用 POST 向服务器端传送数据,则数据类型(Content-
Type)只能是 application/x-www-form-urlencoded, multipart/form-data 或 text/plain中的一种。 - 不会使用自定义请求头(类似于 X-Modified 这种)。
预请求
不同于上面的简单请求,“预请求”要求必须先发送一个 OPTIONS 请求给目的站点,来查明这个跨站请求对于目的站点是不是安全可接受的。这样做,是因为跨站请求可能会对目的站点的数据造成破坏。 当请求具备以下条件,就会被当成预请求处理:
- 请求以 GET, HEAD 或者 POST 以外的方法发起请求。或者,使用 POST,但请求数据为 application/
x-www-form-urlencoded, multipart/form-data 或者 text/plain 以外的数据类型。比如说,用 POST 发送数据类型为 application/xml 或者 text/xml 的 XML 数据的请求。 - 使用自定义请求头(比如添加诸如 X-PINGOTHER)
在这种情况时,后台的应用程序(比如express)必须处理OPTIONS请求或者添加一下代码
|
|
附带证书请求
XMLHttpRequest和访问控制功能,最有趣的特性就是,发送凭证请求(HTTP Cookies和验证信息)的功能。一般而言,对于跨站请求,浏览器是不会发送凭证信息的。但如果将XMLHttpRequest的一个特殊标志位设置为true,浏览器就将允许该请求的发送。
跨域解决方案
- 思路一:含有src或href属性的标签都是可以跨域的(eg:img、script、iframe、link等),使用这个思路可以有很多种跨域的方法
- 思路二:使用CORS,W3C的一个标准,全称“跨域资源共享”(Crocs-origin resource sharing)
通过jsonp跨域
- 原理:script是可以跨域的,而且在跨域脚本中可以直接回调当前脚本的函数。
- 限制:需要创建一个DOM对象并且添加到DOM树,只能用于GET方法
JSONP利用的是script可以跨域的特性,跨域URL返回的脚本不仅包含数据,还包含一个回调:
然后在我们在主站http://a.com中,可以这样来跨域获取http://b.a.com的数据:
|
|
其实jQuery已经封装了JSONP得使用,我们可以这样来
|
|
通过iframe、img跨域
- 原理:所有具有src属性的HTML标签都是可以跨域的,包括img, script
- 限制:需要创建一个DOM对象,只能用于GET方法
|
|
通过CORS
- 原理:服务器设置Access-Control-Allow-OriginHTTP响应头之后,浏览器将会允许跨域请求
- 限制:浏览器需要支持HTML5,可以支持POST,PUT等方法
|
|
window.postMessage
- 原理:HTML5允许窗口之间发送消息
- 限制:浏览器需要支持HTML5,获取窗口句柄后才能相互通信
|
|
在HTML5之前,JSONP已经成为跨域的事实标准了,jQuery都给出了支持。 值得注意的是它只是Hack,并没有产生额外的安全问题。 因为JSONP要成功获取数据,需要跨域资源所在服务器的配合,比如资源所在服务器需要自愿地回调一个合适的函数,所以服务器仍然有能力控制资源的跨域访问。
跨域的正道还是要使用HTML5提供的CORS头字段以及window.postMessage, 可以支持POST, PUT等HTTP方法,从机制上解决跨域问题。 值得注意的是Access-Control-Allow-Origin头字段是资源所在服务器设置的, 访问控制的责任仍然是在提供资源的服务器一方,这和JSONP是一样的。