温馨提示:
-
看懂本文可能需要 -
稍微了解或者开发遇见过跨域问题 -
懂中文 :) -
代码块过长,框框可左右哦 -
您的观看和点赞是对本公众号最大力的支持和鼓励~~
目录
零、跨域的本质
跨域分为两种,一种xhr不能访问不同源的文档,另一种是不同window之间不能进行交互操作
跨域的本质就是网页页面所存在的服务器中的前端代码想要访问其他的域名所存在的服务器。
举一个简单的例子。你打开百度的网页,此时浏览器的地址栏是 http://www.baidu.com,假如在这个页面中有一段js代码,这一段代码发起了一个ajax请求,假定请求的服务端的URL是 http://www.google.com。
那么这个时候浏览器就会怀疑了。你这个网页是百度的网页儿。那么网页里面的代码肯定也是百度的代码了。 而你百度的代码却访问谷歌的服务器,那么此时此刻,即便是按照我们生活中的常识来判断, 发起这个访问也是要经过谷歌服务器的同意的。 如果谷歌不同意,那么就不允许访问了。因此,一般这个时候浏览器会先向谷歌服务器发起一次options请求。 这个请求的参数包含了发起请求的网页的地址。 也就是询问谷歌是否允许来自于百度网页的请求。 此时谷歌的服务器会向浏览器返回一个响应。 告诉浏览器自己是否愿意接受来自百度网页的请求。 如果允许了,那么浏览器就会继续的发起这个请求。 如果谷歌浏览器返回的是拒绝。那么浏览器就会报一个跨域的请求错误。

一、为什么会出现跨域问题
出于浏览器的同源策略限制。同源策略(Sameoriginpolicy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。可以说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。同源策略会阻止一个域的javascript
脚本和另外一个域的内容进行交互。所谓同源(即指在同一个域)就是两个页面具有相同的协议(protocol),主机(host)和端口号(port)
当你打开一个网站时,这个网站开始执行脚本,会检测这个脚本的来源,如果这个脚本的来源与当前网站不同源的话,就会限制其执行,即受到同源策略的限制
MDN上对同源策略的概念解释
同源策略限制了从同一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的重要安全机制。
其中MDN谈到了很重要的一点,IE浏览器的同源是不包含端口号的,即端口号不一致也是属于同源
通俗易懂的说同源策略:不允许A的文档或脚本与B的文档脚本瞎搞在一起,两个相互独立开来,不能直接相互访问
二、什么是跨域
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
当前页面url | 被请求页面url | 是否跨域 | 原因 |
---|---|---|---|
http://www.test.com/ | http://www.test.com/index.html | 否 | 同源(协议、域名、端口号相同) |
http://www.test.com/ | https://www.test.com/index.html | 跨域 | 协议不同(http/https) |
http://www.test.com/ | http://www.baidu.com/ | 跨域 | 主域名不同(test/baidu) |
http://www.test.com/ | http://blog.test.com/ | 跨域 | 子域名不同(www/blog) |
http://www.test.com:8080/ | http://www.test.com:7001/ | 跨域 | 端口号不同(8080/7001) |

特别注意:
-
如果是协议和端口造成的跨域问题“前台”是无能为力的,只能通过后台来解决 -
在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。 “URL的首部”指 window.location.protocol
+window.location.host
,也可以理解为“Domains, protocols and ports must match”。 -
localhost和127.0.0.1虽然都指向本机,但也属于跨域

顶级域(顶级域名):顶级域(或顶级域名),英语:Top-level domains,first-level domains(TLDs),也翻译为国际顶级域名。是互联网DNS等级之中的最高级的域,它保存于DNS根域的名字空间中。顶级域名是域名的最后一个部分,即是域名最后一点之后的字母,例如在http://example.com这个域名中,顶级域是 .com(或.COM),大小写视为相同。 顶级域主要分4类: 通用顶级域(英语:Generic top-level domain,缩写为gTLD),如”.com”、”.net”、”.org”、”.edu”、”.info”等,均由国外公司负责管理; 国家及地区顶级域(英语:Country code top-level domain,缩写为ccTLD),如”.cn”代表中国,”.uk”代表英国等,地理顶级域名一般由各个国家或地区负责管理。 基础建设顶级域(.arpa,过去曾包括在“通用顶级域”内); 测试顶级域。
二级域名:除了顶级域名,还有二级域名(SLD,second-leveldomain),就是最靠近顶级域名左侧的字段。如:http://zh.wikipedia.org中,wikipedia就是二级域名(有资料认为, 在顶级域名后面, 还存在一级域名, 那么zh就是二级域名)。 我国在国际互联网络信息中心(Inter NIC)正式注册并运行的顶级域名是.cn,这也是我国的一级域名。在顶级域名之下,我国的二级域名又分为类别域名和行政区域名两类。类别域名共6个,包括用于科研机构的.ac;用于工商金融企业的.com;用于教育机构的.edu;用于政府部门的.gov;用于互联网络信息中心和运行中心的.net;用于非盈利组织的.org。而行政区域名有34个,分别对应于我国各省、自治区和直辖市。
父域名、子域名(也有资料称为二级域名)一个相对概念,很好理解。如 “www. http://sina.com.cn” 和 “http://news.sina.com.cn” 都是 http://sina.com.cn的子域名(或称为二级域名), http://sina.com.cn 就是父域名。
同样,http://sina.com.cn 其实又可以看作是 .http://com.cn 的子域名;而 http://com.cn 又是 .cn 的一个子域名。
最后做了一张图来总结
img
三、非同源限制
-
无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB -
无法接触非同源网页的 DOM -
无法向非同源地址发送 AJAX 请求
同源策略并非应用于不同源的窗口中的所有对象的所有属性
对于同源策略这里还有一个很关键的点:同源策略并非应用于不同源的窗口中的所有对象的所有属性。
同源策略的适用范围:
它只应用到了其中的大多数属性,尤其是对Document对象的几乎所有属性而言。 凡是包含另一个服务器中文档的窗口或窗体,都是同源策略适用的范围。 如果脚本打开一个窗口,脚本也可以关闭它,但不能以任何方式查看窗口内部。 同源策略还应用于使用XMLHttpRequest生成的HTTP请求。(这也就是为什么我们常用的Ajax请求会受到同源策略影响的原因了)这个对象允许客户端JavaScript生成任意的HTTP请求到脚本所属文档的Web服务器,但是不允许脚本和其他Web服务器通信。
四、跨域解决方法
1. document.domain
document.domain
主要是解决不同window之间不能进行交互操作,且只能适用于主域相同子域不同的情况;
设置document.domain
解决无法读取非同源网页的Cookie
问题
因为浏览器是通过document.domain
属性来检查两个页面是否同源,因此只要通过设置相同的document.domain
,两个页面就可以共享Cookie
// 两个页面都设置
document.domain = 'test.com';
document.domain
的设置是有限制的,我们只能把document.domain
设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com
中某个文档的document.domain
可以设成a.b.example.com
、b.example.com
、example.com中
的任意一个,但是不可以设成c.a.b.example.com
,因为这是当前域的子域,也不可以设成baidu.com
,因为主域已经不相同了。
兼容性:所有浏览器都支持优点:可以实现不同window之间的相互访问和操作;缺点:只适用于父子window之间的通信,不能用于xhr;只能在主域相同且子域不同的情况下使用;
不同的框架之间是可以获取window对象的,但却无法获取相应的属性和方法。
比如,有一个页面,它的地址是http://www.example.com/a.html
, 在这个页面里面有一个iframe,它的src是http://example.com/b.html
, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的:
<script type="text/javascript">
function test(){
var iframe = document.getElementById('ifame');
//可以获取到iframe里的window对象,但该window对象的属性和方法几乎是不可用的
var win = document.contentWindow;
var doc = win.document;//这里获取不到iframe里的document对象
var name = win.name;//这里同样获取不到window对象的name属性
}
</script>
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
这个时候,document.domain就可以派上用场了,我们只要把http://www.example.com/a.html
和 http://example.com/b.html
这两个页面的document.domain都设成相同的域名就可以了。 1.在页面http://www.example.com/a.html
中设置document.domain:
<iframe id = "iframe" src="http://example.com/b.html" onload = "test()"></iframe>
<script type="text/javascript">
document.domain = 'example.com';//设置成主域
function test(){
//contentWindow 可取得子窗口的 window 对象
alert(document.getElementById('iframe').contentWindow);
}
</script>
2.在页面 http://example.com/b.html
中也设置document.domain:
<script type="text/javascript">
//在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
document.domain = 'example.com';
</script>
2. 动态创建script
这个没什么好说的,因为script标签不受同源策略的限制。
function loadScript(url, func) {
var head = document.head || document.getElementByTagName('head')[0];
var script = document.createElement('script');
script.src = url;
script.onload = script.onreadystatechange = function(){
if(!this.readyState || this.readyState=='loaded' || this.readyState=='complete'){
func();
script.onload = script.onreadystatechange = null;
}
};
head.insertBefore(script, 0);
}
window.baidu = {
sug: function(data){
console.log(data);
}
}
loadScript('http://suggestion.baidu.com/su?wd=w',function(){console.log('loaded')});
//我们请求的内容在哪里?
//我们可以在chorme调试面板的source中看到script引入的内容
3. location.hash
原理是利用location.hash来进行传值。
假设域名a.com
下的文件cs1.html要和cnblogs.com
域名下的cs2.html传递信息。
-
cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面 -
cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据 -
同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一旦有变化则获取获取hash值 注:由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe
代码如下: 先是a.com下的文件cs1.html文件:
function startRequest(){
var ifr = document.createElement('iframe');
ifr.style.display = 'none';
ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';
document.body.appendChild(ifr);
}
function checkHash() {
try {
var data = location.hash ? location.hash.substring(1) : '';
if (console.log) {
console.log('Now the data is '+data);
}
} catch(e) {};
}
setInterval(checkHash, 2000);
cnblogs.com域名下的cs2.html:
//模拟一个简单的参数处理操作
switch(location.hash){
case '#paramdo':
callBack();
break;
case '#paramset':
//do something……
break;
}
function callBack(){
try {
parent.location.hash = 'somedata';
} catch (e) {
// ie、chrome的安全机制无法修改parent.location.hash,
// 所以要利用一个中间的cnblogs域下的代理iframe
var ifrproxy = document.createElement('iframe');
ifrproxy.style.display = 'none';
// 注意该文件在"a.com"域下
ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';
document.body.appendChild(ifrproxy);
}
}
a.com下的域名cs3.html
//因为 parent.parent 和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);
4. window.name
关键点:window.name在页面的生命周期里共享一个window.name;
兼容性:所有浏览器都支持;
优点:最简单的利用了浏览器的特性来做到不同域之间的数据传递;不需要前端和后端的特殊配置;
缺点:大小限制:window.name最大size是2M左右,不同浏览器中会有不同约定;
安全性:当前页面所有window都可以修改,很不安全;
数据类型:传递数据只能限于字符串,如果是对象或者其他会自动被转化为字符串,如下; 使用方式:修改window.name的值即可;
5. window.postMessage()
跨文档通信 API:window.postMessage()
postMessage
是h5引入的一个新概念,现在也在进一步的推广和发展中,他进行了一系列的封装,我们可以通过window.postMessage
的方式进行使用,并可以监听其发送的消息
兼容性:移动端可以放心用,但是pc端需要做降级处理
优点:不需要后端介入就可以做到跨域,一个函数外加两个参数(请求url,发送数据)就可以搞定;移动端兼容性好;
缺点:无法做到一对一的传递方式:监听中需要做很多消息的识别,由于postMessage
发出的消息对于同一个页面的不同功能相当于一个广播的过程,该页面的所有onmessage
都会收到,所以需要做消息的判断;
安全性问题:三方可以通过截获,注入html或者脚本的形式监听到消息,从而能够做到篡改的效果,所以在postMessage
和onmessage
中一定要做好这方面的限制;发送的数据会通过结构化克隆算法进行序列化,所以只有满足该算法要求的参数才能够被解析,否则会报错,如function就不能当作参数进行传递;
使用方式:通信的函数,sendMessage
负责发送消息,bindEvent
负责消息的监听并处理,可以通过代码来做一个大致了解;
调用postMessage方法实现父窗口 http://test1.com
向子窗口 http://test2.com
发消息(子窗口同样可以通过该方法发送消息给父窗口)
它可用于解决以下方面的问题:
-
页面和其打开的新窗口的数据传递 -
多窗口之间消息传递 -
页面与嵌套的iframe消息传递 -
上面三个场景的跨域数据传递
// 父窗口打开一个子窗口
var openWindow = window.open('http://test2.com', 'title');
// 父窗口向子窗口发消息(第一个参数代表发送的内容,第二个参数代表接收消息窗口的url)
openWindow.postMessage('Nice to meet you!', 'http://test2.com');
调用message
事件,监听对方发送的消息
// 监听 message 消息
window.addEventListener('message', function (e) {
console.log(e.source); // e.source 发送消息的窗口
console.log(e.origin); // e.origin 消息发向的网址
console.log(e.data); // e.data 发送的消息
},false);
复杂点的例子
Storage.prototype.sendMessage_ = function(type, params, fn) {
if (this.topWindow) {
this.handleCookie_(type, params, fn);
return;
}
var eventId = this.addToQueue_(fn, type);
var storageIframe = document.getElementById('mip-storage-iframe');
var element = document.createElement("a");
element.href = this.origin;
var origin = element.href.slice(0, element.href.indexOf(element.pathname) + 1);
storageIframe.contentWindow.postMessage({
type: type,
params: params,
eventId: eventId
}, origin);
}
Storage.prototype.bindEvent_ = function() {
window.onmessage = function (res) {
// 判断消息来源
if (window == res.source.window.parent &&
res.data.type === this.messageType.RES &&
window.location.href.match(res.origin.host).length > 0) {
var fn = this.eventQueue[res.data.eventId];
fn && fn();
delete this.eventQueue[res.data.eventId];
// reset id
var isEmpty = true;
for (var t in this.eventQueue) {
isEmpty = false;
}
if (isEmpty) {
this.id = 0;
}
}
}.bind(this);
}
6. JSONP
JSONP(JSON with Padding:填充式JSON),应用JSON的一种新方法
JSON、JSONP的区别:
-
JSON返回的是一串数据、JSONP返回的是脚本代码(包含一个函数调用) -
JSONP 只支持get请求、不支持post请求(类似往页面添加一个script标签,通过src属性去触发对指定地址的请求,故只能是Get请求)
拓展:JSONP跨域的script标签请求为什么不受同源策略的限制?
要理解JSONP跨域的script标签请求为什么不受同源策略的限制这个问题的重点就在于**:要执行的脚本是如何判断他的来源的**
可以这么理解,脚本的来源取决于脚本所嵌入的资源的来源,比如说访问A主机的当前HTML文件中有一个script标签,这个script标签的src属性请求了一个js脚本,因为这个脚本是由A主机的HTML文件的嵌入的script标签发起请求获取的,因此这个脚本的来源是属于A主机的。
到了这里,问题的答案也就出来了,jsonp的script标签请求回来的资源与当前域是相同的域,因此不受同源策略的影响
JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get
请求,不支持post
请求
核心思想:网页通过添加一个<script>元素
,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来
要确定jsonp请求是否失败并不容易
①原生实现:
<script src="http://test.com/data.php?callback=dosomething"></script>
// 向服务器test.com发出请求,该请求的查询字符串有一个callback参数,用来指定回调函数的名字
// 处理服务器返回回调函数的数据
<script type="text/javascript">
function dosomething(res){
// 处理获得的数据
console.log(res.data)
}
</script>
② jQuery ajax:
$.ajax({
url: 'http://www.test.com:8080/login',
type: 'get',
dataType: 'jsonp', // 请求方式为jsonp
jsonpCallback: "handleCallback", // 自定义回调函数名
data: {}
});
③ Vue.js
this.$http.jsonp('http://www.domain2.com:8080/login', {
params: {},
jsonp: 'handleCallback'
}).then((res) => {
console.log(res);
})
jsonp虽然很简单,但是有如下缺点:
-
安全问题(请求代码中可能存在安全隐患) -
要确定jsonp请求是否失败并不容易
7. CORS
CORS 是跨域资源分享(Cross-Origin Resource Sharing)的缩写。它是 W3C 标准,属于跨源 AJAX 请求的根本解决方法。CORS背后的思想,就是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败
0、请求分类
请求的类型有简单请求
复杂请求
这两种
-
简单请求:
-
请求方式只能是:
head
,get
,post
-
请求头允许的字段:
Accept
,Accept-Language
,Content-Language
,Last-Event-ID
Content-Type
:application/x-www-form-urlencoded、multipart/form-data、text/plain 三选一 -
复杂请求:没错,不满足上面的,都是我啦!
简单请求:
浏览器:诶,你小子要跨域是吧,我得问问服务器大哥肯不肯!往请求头添加origin
亮一下牌面
有个奇怪现象,谷歌游览器在非跨域情况下,也会发送origin字段

请求头origin字段为当前域
服务器:诶,你是谁,我来看看你的origin,嗯嗯,可以,符合我的要求,放行!顺便告诉你,老夫的规矩!

其中,最重要的就是Access-Control-Allow-Origin
,标识允许哪个域的请求。当然,如果服务器不通过,根本没有这个字段,接着触发XHR
的onerror
,再接着你就看到浏览器的提示xxx的服务器没有响应Access-Control-Allow-Origin字段
//指定允许其他域名访问
'Access-Control-Allow-Origin:http://172.20.0.206'//一般用法(*,指定域,动态设置),3是因为*不允许携带认证头和cookies
//是否允许后续请求携带认证信息(cookies),该值只能是true,否则不返回
'Access-Control-Allow-Credentials:true'
上面第一行说到的Access-Control-Allow-Origin
有多种设置方法:
-
设置 *
是最简单粗暴的,但是服务器出于安全考虑,肯定不会这么干,而且,如果是*
的话,游览器将不会发送cookies
,即使你的XHR
设置了withCredentials
-
指定域,如上图中的 http://172.20.0.206
,一般的系统中间都有一个nginx
,所以推荐这种 -
动态设置为请求域,多人协作时,多个前端对接一个后台,这样很方便
withCredentials
:表示XHR
是否接收cookies和发送cookies,也就是说如果该值是false,响应头的Set-Cookie
,浏览器也不会理,并且即使有目标站点的cookies,浏览器也不会发送。
复杂请求:
最常见的情况,当我们使用put
和delete
请求时,浏览器会先发送option
(预检)请求,不过有时候,你会发现并没有,这是后面我们会讲到缓存。
预检请求
与简单请求不同的是,option请求多了2个字段:Access-Control-Request-Method
:该次请求的请求方式Access-Control-Request-Headers
:该次请求的自定义请求头字段
服务器检查通过后,做出响应:
//指定允许其他域名访问
'Access-Control-Allow-Origin:http://172.20.0.206'//一般用法(*,指定域,动态设置),3是因为*不允许携带认证头和cookies
//是否允许后续请求携带认证信息(cookies),该值只能是true,否则不返回
'Access-Control-Allow-Credentials:true'
//预检结果缓存时间,也就是上面说到的缓存啦
'Access-Control-Max-Age: 1800'
//允许的请求类型
'Access-Control-Allow-Methods:GET,POST,PUT,POST'
//允许的请求头字段
'Access-Control-Allow-Headers:x-requested-with,content-type'
这里有个注意点:Access-Control-Request-Method
,Access-Control-Request-Headers
返回的是满足服务器要求的所有请求方式,请求头,不限于该次请求,我一次性告诉你了,别问我
1、普通跨域请求
只需服务器端设置 Access-Control-Allow-Origin
前后端都需要进行设置
【前端设置】
根据xhr.withCredentials
字段判断是否带有cookie
IE中对CORS的实现是xdr,其它浏览器中的实现就在xhr中
IE
var xdr = new XDomainRequest();
xdr.onload = function(){
console.log(xdr.responseText);
}
xdr.open('get', 'http://www.baidu.com');
......
xdr.send(null);
①原生ajax
var xhr = new XMLHttpRequest(); // IE8/9需用window.XDomainRequest兼容
// 前端设置是否带cookie
xhr.withCredentials = true;
xhr.open('post', 'http://www.domain2.com:8080/login', true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.send('user=admin');
xhr.onreadystatechange = function() {
if (xhr.readyState == 4 && xhr.status == 200) {
alert(xhr.responseText);
}
};
② jQuery ajax
$.ajax({
url: 'http://www.test.com:8080/login',
type: 'get',
data: {},
xhrFields: {
withCredentials: true // 前端设置是否带cookie
},
crossDomain: true, // 会让请求头中包含跨域的额外信息,但不会含cookie
});
③ vue-resource
Vue.http.options.credentials = true
④ axios
axios.defaults.withCredentials = true
实现跨浏览器的CORS
function createCORS(method, url){
var xhr = new XMLHttpRequest();
if('withCredentials' in xhr){
xhr.open(method, url, true);
}else if(typeof XDomainRequest != 'undefined'){
var xhr = new XDomainRequest();
xhr.open(method, url);
}else{
xhr = null;
}
return xhr;
}
var request = createCORS('get', 'http://www.baidu.com');
if(request){
request.onload = function(){
......
};
request.send();
}
【服务端设置】
服务器端对于CORS的支持,主要是通过设置Access-Control-Allow-Origin
来进行的。如果浏览器检测到相应的设置,就可以允许Ajax
进行跨域的访问。
① Java后台
/*
* 导入包:import javax.servlet.http.HttpServletResponse;
* 接口参数中定义:HttpServletResponse response
*/
// 允许跨域访问的域名:若有端口需写全(协议+域名+端口),若没有端口末尾不用加'/'
response.setHeader("Access-Control-Allow-Origin", "http://www.domain1.com");
// 允许前端带认证cookie:启用此项后,上面的域名不能为'*',必须指定具体的域名,否则浏览器会提示
response.setHeader("Access-Control-Allow-Credentials", "true");
// 提示OPTIONS预检时,后端需要设置的两个常用自定义头
response.setHeader("Access-Control-Allow-Headers", "Content-Type,X-Requested-With");
还可以使用springMVC的@CrossOrigin注解实现
② Nodejs后台
var http = require('http');
var server = http.createServer();
var qs = require('querystring');
server.on('request', function(req, res) {
var postData = '';
// 数据块接收中
req.addListener('data', function(chunk) {
postData += chunk;
});
// 数据接收完毕
req.addListener('end', function() {
postData = qs.parse(postData);
// 跨域后台设置
res.writeHead(200, {
// 后端允许发送Cookie
'Access-Control-Allow-Credentials': 'true',
// 允许访问的域(协议+域名+端口)
'Access-Control-Allow-Origin': 'http://www.domain1.com',
/*
* 此处设置的cookie还是domain2的而非domain1,
* 因为后端也不能跨域写cookie(nginx反向代理可以实现),
* 但只要domain2中写入一次cookie认证,后面的跨域接口都能从domain2中获取cookie,
* 从而实现所有的接口都能跨域访问
*/
// HttpOnly的作用是让js无法读取cookie
'Set-Cookie': 'l=a123456;Path=/;Domain=www.domain2.com;HttpOnly'
});
res.write(JSON.stringify(postData));
res.end();
});
});
server.listen('8080');
console.log('Server is running at port 8080...');
③ PHP后台
<?php
header("Access-Control-Allow-Origin:*");
④ Apache
需要使用mod_headers模块来激活HTTP头的设置,它默认是激活的。你只需要在Apache配置文件的<Directory>
, <Location>
, <Files>
或<VirtualHost>
的配置里加入以下内容即可
<Directory "/Users/cindy/dev">
AllowOverride ALL
Header set Access-Control-Allow-Origin *
</Directory>
或者,修改Apache伪静态规则文件.htaccess
<IfModule mod_setenvif.c>
<IfModule mod_headers.c>
<FilesMatch ".(cur|gif|ico|jpe?g|png|svgz?|webp)$">
SetEnvIf Origin ":" IS_CORS
Header set Access-Control-Allow-Origin "*" env=IS_CORS
</FilesMatch>
</IfModule>
</IfModule>
⑤nginx反向代理
www.baidu.com/index.html
需要调用www.sina.com/server.php
,可以写一个接口www.baidu.com/server.php
,由这个接口在后端去调用www.sina.com/server.php
并拿到返回值,然后再返回给index.html
主要是修改nginx.conf
location ~* .(eot|ttf|woff|svg|otf)$ {
add_header Access-Control-Allow-Origin *;
}
上面的eot|ttf|woff|svg|otf,表示请求后缀类型,或者也可以直接写如下代码:
location / {
add_header Access-Control-Allow-Origin *;
}
⑥IIS配置
只需要在IIS添加HTTP响应标头即可
Access-Control-Allow-Headers:Content-Type, api_key, Authorization
Access-Control-Allow-Origin:*
有数据中台的项目,通过中台转发。没数据中台的通过nginx或者其他服务器代理,安全有效
8. web sockets
web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。(同源策略对web sockets不适用)
web sockets原理:在JS创建了web socket之后,会有一个HTTP请求发送到浏览器以发起连接。取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为web sockt协议。
只有在支持web socket协议的服务器上才能正常工作。
var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){
var data = event.data;
}
参考文章
https://blog.csdn.net/qq_38128179/article/details/84956552 什么是跨域?跨域解决方法
https://blog.csdn.net/xiaxiaoxian/article/details/79287458 3分钟弄明白顶级域名二级域名子域名父域名的区别
https://www.cnblogs.com/liuarui/p/11451560.html JSONP跨域的script标签请求为什么不受同源策略的限制?
https://blog.csdn.net/tjcjava/article/details/76468225 什么是跨域?如何解决跨域问题?
https://www.cnblogs.com/JChen666/p/3399951.html 前端解决跨域问题的8种方案(最新最全)
https://www.fujieace.com/html/cors.html 原因:CORS 头缺少 ‘Access-Control-Allow-Origin’ 解决办法
https://my.oschina.net/u/4311057/blog/3254242 JSONP跨域的script标签请求为什么不受同源策略的限制?
https://www.jianshu.com/p/89a377c52b48 没错,就是Access-Control-Allow-Origin,跨域
https://blog.csdn.net/qlin_11/article/details/99302292 前端和后端解决跨域问题
https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS 跨源资源共享(CORS)
https://www.zhihu.com/question/305052491 前后端不分离部署存在跨域吗?
end
您的观看和点赞是对本公众号最大力的支持和鼓励~~
原文始发于微信公众号(一个调皮的bug):什么是跨域?跨域解决方法
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/43408.html