# 解决跨域问题
# 服务器设置
CORS 需要服务器设置header :Access-Control-Allow-Origin。
# jsonp解决跨域
利用script标签的src属性不受同源策略的限制,向服务端发送一个带有callback参数的请求,服务端接收到请求后把数据当做callback的参数返回这个方法。这个方法要在请求前就要定义好,这个方法接受一个参数,用来返回数据。请求后就自动调用了。
这个callback的值(方法名)要事先约定好。
只支持GET请求。
function jsonp(getUrl) {
var script = document.createElement('script');
script.src = getUrl + '?callback=fn';
document.body.appendChild(script);
}
// 定义好方法获取数据
function fn (data) {
console.log(data)
}
jsonp(getUrl)
服务端
// 后端接收到请求后把数据传入这个函数并返回这个
var data = {}
fn(data)
# nginx反向代理
当前域名下请求另一个域名下的资源或者接口,肯定会跨域,无法请求,可以通过nginx代理到另一个域名的接口。
通过配置nginx.conf文件下server的proxy_pass来实现代理。
比如要请求另一个域名的api http://www.b.com/api/user?name=xxx&age=xxx
server {
listen 8080; // 监听当前域名断开
server_name http://www.a.com; // 监听当前域名,本地启动项目为localhost或者ip地址
location / {
root C:/GitProject/tourbox;
index index.html index.htm;
}
// 监听某个api 然后代理到另一个域名下的api 或者全部代理
// 请求http://www.a.com/api/user?name=&age=会被代理到http://www.b.com/api/user?name=&age=
location /api {
proxy_pass http://www.b.com/api;
}
}
# postMessage跨域
postMessage可以允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。
otherWindow.postMessage(message, targetOrigin, [transfer])
otherWindow:其他窗口的一个引用,比如 iframe 的 contentWindow 属性、执行 window.open 返回的窗口对象、或者是命名过或数值索引的 window.frames。
message: 将要发送到其他 window 的数据。
targetOrigin: 通过窗口的 origin 属性来指定哪些窗口能接收到消息事件,其值可以是字符串"*"(表示无限制)或者一个 URI。在发送消息的时候,如果目标窗口的协议、主机地址或端口这三者的任意一项不匹配 targetOrigin 提供的值,那么消息就不会被发送;只有三者完全匹配,消息才会被发送。
transfer(可选):是一串和 message 同时传递的 Transferable 对象. 这些对象的所有权将被转移给消息的接收方,而发送一方将不再保有所有权。
父页面:
<body>
<h1>我是父页面</h1>
<p><button id="btn">发送子页面消息</button></p>
<iframe id="iframe" src="http://localhost:3009/" frameborder="0"></iframe>
<script>
var iframe = document.getElementById('iframe');
var btn = document.getElementById('btn');
// 像子页面发送数据
btn.onclick = function() {
iframe.contentWindow.postMessage('父页面数据', '*'); // * 代表所有都可以接收
}
// 接收子页面发送的数据
window.addEventListener("message", receiveSubMsg, false);
function receiveSubMsg (event) {
console.log(event.data); // 子页面数据
}
</script>
</body>
子页面:
<body>
<h1>我是子页面</h1>
<script>
// 监听message
window.addEventListener("message", receiveMsg, false);
function receiveMsg (event) {
console.log(event.data); // 父页面数据
}
// 像父页面发送数据
var btn = document.getElementById('btn');
btn.onclick = function() {
window.parent.postMessage('父页面数据', '*'); // 通过window.parent像父页面发送数据
}
</script>
</body>
# 使用window.name + iframe
window.name
有一个奇妙的性质,如果当前页面设置了window.name
,在不关闭当前页面的情况下,即使使用window.location.href = 'xxx'
,进行跳转到其他页面window.name
也还会保留。
所以可以结合iframe跳转到设置了window.name
不同源的页面,然后再跳转到同源下的空白页面,这个空白页面会保留不同源页面设置的window.name
,最后获取这个同源下空白页面的window.name
就可以解决跨域的问题了。
http://www.a.com
index.html
empty.html
http://www.b.com
index.html
http://www.a.com/index.html
<body>
<h1>我是父页面</h1>
<!-- 第一次跳转到不同源页面 -->
<iframe id="iframe" src="http://www.b.com/index.html" frameborder="0" onload="load()"></iframe>
<script>
var iframe = document.getElementById('iframe')
var first = true
function load() {
// 第一次加载后设置了window.name后跳转到同源empty空页面下
if (first) {
iframe.src = 'http://www.a.com/empty.html'
first = false
} else {
// 第二次跳转到同源empty空页面下获取当前iframe页面的name属性
console.log(iframe.contentWindow.name) // hhhh
}
}
</script>
</body>
http://www.b.com/index.html
<body>
<h1>我是不同源页面</h1>
<script>
// 设置window.name
window.name = 'hhhh'
</script>
</body>
# location.hash + iframe
还是通过另一个同源页面做中转
实现原理:当前页面可以通过iframe跳转给不同源页面传递一个hash值,不同源页面通过也通过iframe跳转到和当前同源的空页面传递一个hash值,然后在这个同源的空页面把hash值传给当前页面。
http://www.a.com/index.html
<body>
<h1>我是父页面</h1>
<iframe id="iframe" src="http://localhost:3009/index.html#changzhen" frameborder="0" ></iframe>
<script>
window.onhashchange = function () {
// 检测hash的变化
console.log(456, location.hash) // #monkey
}
</script>
</body>
http://www.b.com/empth.html
<body>
<h1>empty.html</h1>
<script>
// 同源空页面将结果传给父页面的hash值中,两次iframe跳转可通过parent.parent访问父页面
window.parent.parent.location.hash = location.hash
</script>
</body>
http://www.b.com/index.html
<body>
<h1>我是不同源页面</h1>
<script>
console.log(location.hash) // #changzhen
// 通过iframe再跳转到另一个同源空页面,把hash值传给它
var iframe = document.createElement('iframe')
iframe.src = 'http://localhost:3008/empty.html#monkey'
document.body.appendChild(iframe)
</script>
</body>
# document.domain + iframe
这种方式只能用于二级域名相同的情况下。
比如 a.test.com 和 b.test.com 就属于二级域名,它们都是 test.com 的子域名
只需要给页面添加 document.domain ='test.com' 表示二级域名都相同就可以实现跨域。
a.test.com/index.html
<body>
<h1>当前二级域名页面</h1>
<iframe id="iframe" src="http://b.test.com:3000/index.html" frameborder="0" onload="load()" ></iframe>
<script>
// 设置document.domain为主域名,都表示二级域名
document.domain = 'test.com'
function load() {
console.log(iframe.contentWindow.a) // 10
}
</script>
</body>
b.test.com/index.html
<body>
<h1>另一个二级域名页面</h1>
<script>
// 设置document.domain为主域名,都表示二级域名
document.domain = 'test.com'
var a = 10
</script>
</body>