什么是跨域
当一个请求url的协议、域名、端口三者之间任意一个与当前页面url不同即为跨域
注意:localhost和127.0.0.1虽然都指向本机,但也属于跨域。
浏览器执行javascript脚本时,会检查这个脚本属于哪个页面,如果不是同源页面,就不会被执行。
为什么会出现跨域问题?
跨域并不是请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。之所以会跨域,是因为受到了同源策略的限制,同源策略要求源相同才能正常进行通信,即协议、域名、端口号都完全一致,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响。
什么是同源策略及其限制
同源策略限制从一个源加载的文档或脚本如何与来自另一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。它的存在可以保护用户隐私信息,防止身份伪造等(读取Cookie)。
非同源限制
1、无法读取非同源网页的 Cookie、LocalStorage 和 IndexedDB
2、无法接触非同源网页的 DOM
3、无法向非同源地址发送 AJAX 请求
但是有三个标签是允许跨域加载资源:
1.<img src=XXX>
2.<link href=XXX>
3.<script src=XXX>
解决办法
JSONP
JSONP 是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,兼容性好(兼容低版本IE),缺点是只支持get请求,不支持post请求。
核心思想: 网页通过添加一个<script>
元素,向服务器请求 JSON 数据,服务器收到请求后,将数据放在一个指定名字的回调函数的参数位置传回来。
$.ajax({
type:"get", //请求方式
/*jsop跨域,只能使用get方法,如果我们设置的是post方法,jQuery自动跳转为get方法
在jQuery中会先判断是否为同源请求,如果同源,那么这是的是get就是get,设置的是post就是post,如果不同元,无论设置什么都改为get*/
async:true, //是否异步
url:"https://url",
dataType:"jsonp", //跨域json请求一定是jsonp
data:{"id":getQueryString('data')}, //请求参数
beforeSend: function() {
//请求前的处理
},
success: function(data) {
console.log(data)
//请求成功处理,和本地回调完全一样
},
complete: function() {
//请求完成的处理
},
error: function() {
//请求出错处理
}
})
例子:
function deal(res){
console.log(res);
}
$.ajax({
//baidu搜索(百度可跨域的接口): https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su
url:'https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su',
type:"GET",//jsop跨域,只能使用get方法,如果我们设置的是post方法,jQuery自动跳转为get方法
dataType:'jsonp',
data:{
wd:'json',
cb : 'deal'//接收jsonp返回的数据必须要用的一个参数 并且客户端中必须有一个和cb值相同的函数名
}
});
jsonp原理:
1·判断请求与当前页面的域 是否同源。如果同源则发送正常的ajax请求
2.如果不同源,生成一个script标签
3、生成一个随机的callback名字,还得创建一个名为这个随机名字的方法
4、设置script标签的src,设置为要请求的接口 因为它不受跨域的限制
5、将callback作为参数拼接在后面
6、后端接收到请求后,开始准备要返回的数据
7、后端拼接数据,将要返回的数据用callback的值和括号包裹起来
ex:callback = ded223 要返回的数据为 {“a”:11,“b”:55}
就要拼接为: ded223({“a”:11,“b”:55})
8、将内容返回
9、浏览器接收到内容,会当做js代码来执行
10、从而执行名为ded223的方法,这样我们就接受到了后端返回给我们的对象
PHP端修改header(XHR2方式)
在php接口脚本中加入以下两句即可:
header(‘Access-Control-Allow-Origin:*’);//允许所有来源访问
header(‘Access-Control-Allow-Method:POST,GET’);//允许访问的方式
客户端 iframe
window.postMessage(要传递的数据, 允许拿到这个数据的源)
H5的解决办法 通过自己的后端代理
//我是父窗口(不同源 跨域了) 我的端口号是80
<iframe src="http://127.0.0.1:5500/demo.html" frameborder="1" id="oIfr"></iframe>
<script>
// 获取子窗口的数据
var oIfr = document.getElementById('oIfr');
// 子窗口加载完成之后执行
oIfr.onload = function(){
// console.log(oIfr.contentWindow.demo);
// window.postMessage(要传递的数据, 允许拿到这个数据的源) H5的解决办法
oIfr.contentWindow.postMessage(f, 'http://127.0.0.1:5500');
}
// 接收不同源子窗口床底过来的数据 接收信息的事件 结合着postMessage来用
window.onmessage = function(e){
console.log('我是父窗口,接收到子窗口给我的信息:' , e.data);
}
</script>