关于跨域,之所以会出现是因为"同源策略"
那什么是同源策略?我们说当两个地址如果在协议、域名、端口号其中之一不一样,我们称为跨域。
为什么不支持跨域?
cookie,localStorage 不支持跨域
当用户登录银行网站,而http是没有状态的,不知道是谁登陆,网站会发给客户个cookie,给你发个sessionID标识是当前客户,假设当前没有同源问题,然后用户访问了一个恶意网站,然后给恶意网站发送ajax请求,请求的时候,将浏览器给客户的id给了恶意网站,然后后恶意网站可以拿着客户给的id在去访问银行,相当于伪造用户,不安全
DOM元素 iframe
在我们的页面嵌入别人的页面,我们在此页面操作别的页面,前提是必须是同域,假设用户输入账号密码登录,我的网站可以操作里面的页面,那么用户的账号密码就能被看到,着也不安全
ajax不支持跨域 接口只要知道链接,都可以访问
这么多问题,我们为什么还要跨域,常见比如前后端分离?
前后端不在同一个服务器地址上,这两者想实现通信,,怎么通信?需要一些手段,,有一些是协商好的,或者聪明点的办法
- jsop 缺点 xxs攻击
- cors
- postMessage 两个页面之间进行通信
- window.name 到底name能干嘛
- location.hash sta框架比较多
- http-propxy webpack 有个代理 有个中间件
- nginx 配
- websocket 页面之间的通信,但是没有跨域的问题
- 图像ping 和Comet
- document.domain 二级域名和一级域名,同一个域下的,子域和父域的
- jsop 缺点
最典型的是百度搜索框

这是一个标准的jsonp接口,它原理呢,就是利用我们<link>,script,img,等引入方式是不受通源策略的,打开地址https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=a&cb=show出现show({q:"b",p:false,s:["baidu","bt","btchina","beyond","bbs","bbc","blog","bobo组合","bb霜"]});
function show(data){
console.log(data)
}
show({q:"b",p:false,s:["baidu","bt","btchina","beyond","bbs","bbc","blog","bobo组合","bb霜"]});
等同于
function show(data){
console.log(data)
}
// show({q:"b",p:false,s:["baidu","bt","btchina","beyond","bbs","bbc","blog","bobo组合","bb霜"]});
<script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=a&cb=show"></script>//这个文件域实现跨域
我们可能从来没写过什么全局函数,也没说是怎么声明的,我们怎么用呢?一般我们会用第三方的包,也可以自己写
//<!--<script>-->
function jsonp({url,params,cb}){ //params:{wd:'a'} cb:'show'
return new Promise((resolve,reject) => {
let script = document.createElement('script');
window[cb] = function(data){
resolve(data);
document.body.removeChild(script)
}
params = {...params,cb} // params = {wd:'a',cb:'show'}
let arr = [];
for(let key in params){
arr.push(`${key}=${params[key]}`);
} // arr[wd='a','cb='show']
script.src = `${url}?${arr.join('&')}`;// arr.join('&') = wd='a'&'cb='show'
document.body.appendChild(script);
})
}
//jsonp会帮我们创建回调,创建script标签
jsonp({
url:'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',
params:{wd:'a'},
cb:'show'
}).then(data => {
console.log(data)
})
// show({q:"b",p:false,s:["baidu","bt","btchina","beyond","bbs","bbc","blog","bobo组合","bb霜"]});
// </script>
// <!-- <script src="https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?wd=a&cb=show"></script> -->
由于我们是使用引入script标签的方法,因此我们只能请求get方法,而且引入进来的script脚本可能会受到恶意攻击(xss),虽然很常用,但是不建议使用。 h5请参考www.runoob.com/json/json-j…
- cors
这个跟前端几乎没有 关系,一般类似于后台的白名单,而且后台仅仅需要加几行代码
//res
let xhr = new XMLHttpRequest;
document.cookie = 'name=哇美女';
xhr.withCredentials = true; //cookie跨域需要上传凭证
xhr.open('PUT','http://localhost:4000/getData',true);
xhr.setRequestHeader('name','zdl');
xhr.onreadystatechange = function(){
if(xhr.readyState === 4){
if(xhr.status >= 200 && xhr.status < 300 || xhr.status === 304){
console.log(xhr.response)
}
}
}
//res
let whitlist = ["http://localhost:3000"];
app.use(function(req,res,next){
let origin = req.hearders.origin;
if(whitlist.includs(origin)){
res.setHeader('Access-control-origin',origin);//源
res.setHeader('Access-control-Headers',name);//携带头
res.setHeader('Access-control-Method',put);//方式
res.setHeader('Access-control-Credentials',true);//cookie可以跨域
res.setHeader('Access-control-Expose-Headers','name');//允许返回头
}
})
- postMessage 两个页面之间进行通信
简单来说就是iframe通信
//目前是3000 端口a页面 http://localhost:3000/a.html
//<iframe src="http://localhost:4000/b.html" id = "frame" load()></iframe>
function load(){
let frame = document.getElementById('frame');
frame.contentWindow.postMessage('我美吗','http://localhost:4000/b.htm');
window.onmessage = function(e){
console.log(e.data)
}
}
//目前是4000 端口b页面 http://localhost:4000/b.html
//<iframe src="http://localhost:4000/b.html" id = "frame" load()></iframe>
window.onmessage= function(e){
console.log(e.data);
e.source.postMessage('你很美',e.origin)
}
- window.name 到底name能干嘛
- a和b是同域的 http://localhost:3000
- c是独立的 http://localhost:4000
- a获取c的数据
- a先引用c, c把值放到window.name,把a的引用地址改到b
//目前是3000 端口a页面 http://localhost:3000/a.html
//<iframe src="http://localhost:4000/c.html" id = "frame" onload = "load()"></iframe>
function load(){
let first = true;
if(first){//第一次加载,c将name放进去了
let iframe = document.getElementById('frame');
iframe.src = 'http://localhost:3000/b.html';//改变引用地址,出发load事件
first = false;
frame.contentWindow.postMessage('我美吗','http://localhost:3000/b.htm');
window.onmessage = function(e){
console.log(e.data)
}
}else{//a和b是同域
iframe.contentWindow.name //此时a和b是同域,可以取值
}
}
//c页面
window.name = 'fsfa'
- location.hash sta框架比较多
路径后面的hash也可以通信
目的: a访问c
a将hash值传递给c,c可以收到hash值,但是a不能拿c的结果,c以同样的方式传递给b ,然后b将结果放到hash中
//a页面,这样c可以取到hash值
//<iframe src="http://localhost:4000/c.html#fdhd" id = "frame" </iframe>
//c
console.log(location.hash);
let iframe = document.creatElement('iframe');
iframe.src = "http://localhost:3000/b.html#dsafaf";
document.body.apendChild(iframe);//将hach传递给b
//b b和a同域,可以传递
window.parent.parent.location.hash = location.hash
//a
window.onhashchange = function(){
console.log(location.hash)
}
比较少用,同样是通过iframe的src传递 src = http://localhost:4000/c.html#dsfdf 只不过是通过hash传递
-
http-propxy webpack 有个代理 有个中间件
-
nginx 配或者命令
-
websocket 页面之间的通信,但是没有跨域的问题,同样能实现数据之间的传递
优点就是传播速度快,传播平等,与ajax不同的是服务器能主动和websocket通信,双工,ajax是单双工 请参考阮一峰websoke介绍,很详细
//高级api不兼容,,有个库 socket.io兼容
let socket = new WebSocket('ws://localhost:3000');
//链接成功会触发onopen 事件
ws.onopen = function(evt) {
console.log("Connection open ...");
ws.send("Hello WebSockets!");
};
//打开
//接收
ws.onmessage = function(evt) {
console.log( "Received Message: " + evt.data);
ws.close();
};
//关闭
ws.onclose = function(evt) {
console.log("Connection closed.");
};
- document.domain
它解决了某些问题,但不是所有的,
域名关系:二级域名和一级域名
找到hosts配置文件配置域名:
127.0.0.1.a.ah.cn
127.0.0.1.b.ah.cn
同一个域下的,子域和父域的
http://localhost:3000/a.html 和 http://localhost/two:3000/b.html
//a是http://a.ah.cn:3000/a.html
//<iframe src="http://b.ah.cn:3000/b.html" id = "frame" onload="load"></iframe>
document.domain = 'ah.cn';//解决方法各自加domain
function load(){
console.log(frame.contentWindow.a)//一般会跨域
}
//b
document.domain = 'ah.cn';
var a = 100