##http://store.company.com/dir2/other.html<span style="font-size: 14px;"></span> |
Success<span style="font-size: 14px;"></span>
|
http://store.company.com/dir/inner/other.html <span style="font-size: 14px;"></span> |
Success<span style="font-size: 14px;"></span>
|
https://store.company.com/secure.html <span style="font-size: 14px;"></span> |
Failed<span style="font-size: 14px;"></span>
|
Different protocols (<span style="font-size: 14px;"></span>https<span style="font-size: 14px;"></span> and<span style="font-size: 14px;"></span>http<span style="font-size: 14px;"></span> )<span style="font-size: 14px;"></span>
|
##http://store.company. com:81/dir/etc.html<span style="font-size: 14px;"></span>
| Failed<span style="font-size: 14px;"></span> | Different ports (81 and 80) |
http://news.company.com/dir/other.html<span style="font-size: 14px;"></span>
| Failed<span style="font-size: 14px;"></span> | Different domain names (
<span style="font-size: 14px;"></span>news<span style="font-size: 14px;"></span> and <span style="font-size: 14px;"></span>store<span style="font-size: 14px;"></span> ) <span style="font-size: 14px;"></span>
|
If it is not from the same origin, three behaviors will be restricted:
##Cookie, LocalStorage and IndexDB cannot be read<span style="font-size: 14px;"></span>
DOM cannot be obtained<span style="font-size: 14px;"></span>
AJAX request cannot be sent<span style="font-size: 14px;"></span>
Avoid the same-origin policy (cross-domain)<span style="font-size: 14px;"></span>
Cookie<span style="font-size: 14px;"></span>
document.domain<span style="font-size: 14px;"></span>
Cookie is a small piece of information written by the server to the browser, which can only be shared by web pages of the same hospital. However, the first-level domain names of the two web pages are the same, but the second-level domain names are different. The browser allows sharing of cookies through <span style="font-size: 14px;"></span>document.domain<span style="font-size: 14px;"></span>
<span style="font-size: 14px;"></span>
For example, suppose a script in the document executes the following statement at <span style="font-size: 14px;"></span>http://store.company.com/dir/page.html<span style="font-size: 14px;"></span>
:<span style="font-size: 14px;"></span>
<span style="font-size: 14px;">document.domain = "company.com"<br></span>
Copy after login
At this time,<span style="font-size: 14px;"></span>http://news.company.com/dir/other.html<span style="font-size: 14px;"></span>
and<span style="font-size: 14px;"></span>http://store.company.com/dir/other.html<span style="font-size: 14px;"></span>
can be passed<span style="font-size: 14px;"></span>document .cookie<span style="font-size: 14px;"></span>
to set or get cookies, that is, shared cookies. <span style="font-size: 14px;"></span>
But this method applies to Cookie and iframe windows, LocalStorage and IndexDB cannot circumvent the same origin policy through this method. <span style="font-size: 14px;"></span>
iframe<span style="font-size: 14px;"></span>
If two web pages have different sources, they cannot get each other’s DOM. A typical example is <span style="font-size: 14px;"></span> If the iframe<span style="font-size: 14px;"></span>
window and the window opened by the <span style="font-size: 14px;"></span>window.open<span style="font-size: 14px;"></span>
method are not from the same source as the parent window, it will Report an error. <span style="font-size: 14px;"></span>
At this time, if the first-level domain name of the two windows is the same, but the second-level domain name is different, then set <span style="font-size: 14px;"></span>document.domain<span style="font-size: 14px;"></span>
Attribute, you can circumvent the same-origin policy. <span style="font-size: 14px;"></span>
For websites with completely different origins, there are currently three methods to solve the communication problem between cross-domain windows. <span style="font-size: 14px;"></span>
fragment identifier<span style="font-size: 14px;"></span>
window.name<span style="font-size: 14px;"></span>
Cross-document messaging API<span style="font-size: 14px;"></span>
Fragment identifier<span style="font-size: 14px;"></span>
The fragment identifier refers to the part after # in the URL, that is, <span style="font-size: 14px;"></span>http://store.company.com/dir/other.html# fragment<span style="font-size: 14px;"></span>
<span style="font-size: 14px;"></span>#fragment<span style="font-size: 14px;"></span>
(location.hash), if only the fragment identifier is changed, the page will not be refreshed. <span style="font-size: 14px;"></span>
The parent window can write information to the fragment identifier of the child window, and the child window listens to the <span style="font-size: 14px;"></span>hashchange<span style="font-size: 14px;"></span>
event Get notified. <span style="font-size: 14px;"></span>
window.name<span style="font-size: 14px;"></span>
Each iframe has a window that wraps it. This window is a child window of the top window, so naturally <span style="font-size: 14px;"></span>window.name<span style="font-size: 14px;"></span>
attribute refers to the name of the current window. The biggest feature of this attribute is that, regardless of whether it has the same source or not, as long as the window is in the same window, All pages within have read and write permissions for window.name. <span style="font-size: 14px;"></span>
The value of window.name can only be in the form of a string. The maximum capacity of this string can be about 2M or even larger, depending on different browsers. <span style="font-size: 14px;"></span>
例如,想要在<span style="font-size: 14px;">http://example/a.html</span>
中获取<span style="font-size: 14px;">http://company.com/data.html</span>
中的数据,可以在a.html中使用一个隐藏的iframe,将iframe的src首先设置为<span style="font-size: 14px;">http://company.com/data.html</span>
,将其window.name设置为所需的数据内容,随后再将这个iframe的src设置为跟a.html页面同一个域的一个页面,不然a.html获取不到该iframe的window.name
<span style="font-size: 14px;">window.postMessage</span>
这是html5中新引入的一个API,可以使用它向其它的window对象发送消息,无论这个window对象属于同源还是不同源。
例如,父窗口<span style="font-size: 14px;">http://example/a.html</span>
向子窗口<span style="font-size: 14px;">http://company.com/data.html</span>
发送消息:
<span style="font-size: 14px;">var newWin = window.open('http://company.com/data.html', 'title')<br>newWin.postMessage('Hello World!'. 'http://company.com/data.html')<br></span>
Copy after login
<span style="font-size: 14px;">window.postMessage</span>
方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源,即<span style="font-size: 14px;">协议</span>
+<span style="font-size: 14px;">端口</span>
+<span style="font-size: 14px;">域名</span>
,也可以设置为<span style="font-size: 14px;">*</span>
,表示不限制域名。
子窗口向父窗口发送消息的写法类似:
<span style="font-size: 14px;">window.opener.postMessage('Nice to see you', 'http://example/a.html')<br></span>
Copy after login
子窗口和父窗口都可以通过<span style="font-size: 14px;">message</span>
时间,监听对方的消息。
<span style="font-size: 14px;">window.addEventListener('message', function(e) {<br> // ...<br>}, false)<br></span>
Copy after login
<span style="font-size: 14px;">message</span>
事件的事件对象<span style="font-size: 14px;">event</span>
有以下三个属性:
通过<span style="font-size: 14px;">window.postMessage</span>
,也可以读写其他窗口的<span style="font-size: 14px;">localStorage</span>
AJAX
同源策略规定,AJAX请求只能发给同源的网址,否则就报错,但是有三种方法可以规避这个限定:
JSONP
JSONP是服务器与客户端跨源通信的常用方法。基本思想是利用<span style="font-size: 14px;"><script></span>
请求脚本能够跨域访问的特性,先定义了一个回调方法,然后将其作为url参数的一部分发送到服务端,服务端通过字符串拼接的方式将数据包裹在回调方法中,再返回回来。
<span style="font-size: 14px;">// 网页动态插入`<script>`元素<br>function addScriptTag(src) {<br> var script = document.createElement("script")<br> script.setAttribute("type", "text/javascript")<br> srcipt.src = src<br> document.body.appendChild(script)<br>}<br><br>window.onload = function() {<br> addScriptTag('http://example.com/ip?callback=foo')<br>}<br><br>function foo(data) {<br> // ...<br>}<br></span>
Copy after login
WebSocket
WebSocket是一种通信协议,使用<span style="font-size: 14px;">ws://</span>
(非加密)和<span style="font-size: 14px;">wss://</span>
(加密)作为协议前缀。该协议不实行同源政策,只要服务支持,就可以通过它进行跨源通信。
浏览器发出的WebSocket请求的头信息中含有<span style="font-size: 14px;">Origin</span>
字段,表示该请求的请求源,即发自哪个域名。(加入白名单)
CORS
跨域资源共享(Cross-Origin Resource Sharing,CORS)是一种使用额外的HTTP头来使一个用户代理从一个不同于当前站点(域)的服务器获取指定的资源的机制。用户代理使用跨域HTTP请求来获取与当前文档不同域、不用协议或端口的资源。
出于安全考虑,浏览器会限制从脚本内发起的跨域HTTP请求。而跨域资源共享(CORS)机制允许web应用服务器进行跨域访问控制,从而使跨域数据传输得以安全进行。浏览器支持在API容器中(例如<span style="font-size: 14px;">XMLHttpRequest</span>
或<span style="font-size: 14px;">Fetch</span>
)使用CORS,以降低跨域HTTP请求所带来的风险。
跨域资源共享标准允许在下列场景中使用跨域HTTP请求:
由XMLHttpRequest或Fetch发起的跨域HTTP请求;
web字体(CSS中通过<span style="font-size: 14px;">@font-face</span>
使用跨域字体资源),因此,网站就可以发布TrueType字体资源,并只允许已授权网站进行跨站调用;
WebGL贴图;
使用drawImage将Images/video画面绘制到canvas;
样式表(使用CSSOM);
Scripts(未处理的异常)。
浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)
只要同时满足以下两大条件,就属于简单请求:
1 请求方法是以下三种方法之一:
<span style="font-size: 14px;">- HEAD<br>- GET<br>- POST<br></span>
Copy after login
2 HTTP的头信息不超出以下几种字段:
<span style="font-size: 14px;">- Accept<br>- Accept-Language<br>- Content-Language<br>- Last-Event-ID<br>- Content-Type:(只限三个值:application/x-www-form-urlencoded、multipart/from-data、text/plain)<br></span>
Copy after login
只要不同时满足上面两个条件,就属于非简单请求
简单请求
对于简单请求,浏览器会在请求头部增加一个<span style="font-size: 14px;">Origin</span>
字段。这个字段用来说明本次请求来自哪个源(协议+域名+端口)。服务器根据这个值决定是否同意这次请求。
如果<span style="font-size: 14px;">Origin</span>
指定的源不在许可范围内,服务器会返回一个正常的HTTP回应。而这个回应的头信息不包含<span style="font-size: 14px;">Access-Control-Allow-Origin</span>
字段,从而会抛出错误被<span style="font-size: 14px;">XMLHttpRequest</span>
的<span style="font-size: 14px;">onerror</span>
函数捕获,(回应的状态码有可能是200)。
如果<span style="font-size: 14px;">Origin</span>
指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段
<span style="font-size: 14px;">Access-Control-Allow-Origin: ...<br>Access-Control-Allow-Credentials: true<br>Access-Control-Expose-Headers: callback<br>Content-Type: text/html; charset=utf-8<br></span>
Copy after login
<span style="font-size: 14px;">Access-Control-Allow-Origin</span>
: 必须。值要么是请求时<span style="font-size: 14px;">Origin</span>
的值,要么是'*'
<span style="font-size: 14px;">Access-Control-Allow-Credentials</span>
: 可选。布尔值,决定是否允许发送Cookie,不需要则删除该字段。
<span style="font-size: 14px;">Access-Control-Expose-Headers</span>
: 可选。CORS请求时,<span style="font-size: 14px;">XMLHttpRequest</span>
对象的 <span style="font-size: 14px;">getResponseHeader()</span>
方法只能拿到6个基本字段:<span style="font-size: 14px;">Cache-Control</span>
、<span style="font-size: 14px;">Content-Language</span>
、<span style="font-size: 14px;">Content-Type</span>
、<span style="font-size: 14px;">Expires</span>
、<span style="font-size: 14px;">Last-Modified</span>
、<span style="font-size: 14px;">Pragma</span>
。如果想拿到其他字段,就需要在<span style="font-size: 14px;">Access-Control-Expose-Header</span>
里面指定。上面的例子指定为callback,则可以使用<span style="font-size: 14px;">getResponseHeader(callback)</span>
获取callback字段的值。
CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发送到服务器,一方面要服务器同意,指定<span style="font-size: 14px;">Access-Control-Allow-Credentials</span>
字段,另一方面,开发者需要在AJAX请求中设置<span style="font-size: 14px;">withCredentials</span>
属性:
<span style="font-size: 14px;">var xhr = new XMLHttpRequest()<br>xhr.withCredentials = true<br></span>
Copy after login
否则,即使服务器同意发送Cookie,浏览器也不会发送。
需要注意的是,如果要发送Cookie,<span style="font-size: 14px;">Access-Control-Allow-Origin</span>
就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源策略,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且跨域的原网页中的<span style="font-size: 14px;">document.cookie</span>
操作也无法获取嗷服务器域名下的Cookie。
非简单请求
非简单请求是那种对服务器有特殊要求的请求,比如请求方法是<span style="font-size: 14px;">PUT</span>
或<span style="font-size: 14px;">DELETE</span>
,或者<span style="font-size: 14px;">Content-Type</span>
字段的类型是<span style="font-size: 14px;">application/json</span>
。
非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为“预检”请求。
浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP操作和头信息字段。只有得到肯定答复,浏览器才会发出正式的<span style="font-size: 14px;">XMLHttpRequest</span>
请求,否则就报错。
“预检”请求用请求方法是<span style="font-size: 14px;">OPTIONS</span>
,表示这个请求是用来询问的。头信息里面,关键字段是<span style="font-size: 14px;">Origin</span>
,表示请求来自哪个源。
还有以下两个特殊字段:
服务器返回的响应:
<span style="font-size: 14px;">Access-Control-Allow-Methods: ...<br>Access-Control-Expose-Headers: callback<br>Access-Control-Allow-Credentials: true<br>Access-Control-Max-Age: 1728000<br></span>
Copy after login
Access-Control-Allow-Methods: 必须。逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。为了避免多次“预检”行为。
Access-Control-Expose-Headers: If the browser request includes <span style="font-size: 14px;">Access-Control-Request-Headers</span>
field, the <span style="font-size: 14px;">Access-Control-Allow-Headers</span>
field is required. It is also a comma-separated string indicating all header fields supported by the server, not limited to the fields requested by the browser in "preflight".
Access-Control-Allow-Credentials: has the same meaning as a simple request.
Access-Control-Max-Age: The validity period of this preflight request.
Comparison of CORS and JSONP
CORS has the same purpose as JSONP, but is more powerful than JSONP.
JSONP only supports <span style="font-size: 14px;">GET</span>
requests, CORS supports all types of HTTP requests. The advantage of JSONP is that it supports older browsers and can request data from websites that do not support CORS.
Related recommendations:
Steps to implement lazy loading and cross-domain implementation using Js
How to understand Js cross-domain
Detailed explanation of how to enable laravel's cross-domain function