1. JSONP
JSONP是服务器与客户端跨源通信的常用方法。最大特点就是简单适用,老式浏览器全部支持,服务器改造非常小。
它的基本思想是,网页通过添加一个<script>
元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
Example
使用如下接口 https://api.asilu.com/ip/
<!DOCTYPE html>
<body>
<script>
// 设置回调函数
function foo(data){
console.log(data)
}
</script>
<script src='https://api.asilu.com/ip?callback=foo'></script>
</body>
// 输出
{
"ip": "118.250.83.107",
"dz": "湖南省长沙市",
"wl": "电信"
}
mock测试
<!DOCTYPE html>
<body>
<script>
function foo(e){
console.log(e)
}
</script>
<script src='http://localhost:8080/test?callback=foo'>
</script>
</body>
// 后端mock
router.get('/test',function(req,res){
var cb = req.query.callback
var mockData = {
a1:'abc',
a2:'123',
a3:'hello'
}
res.send(cb + '(' + JSON.stringify(mockData) +')')
})
// 输出
Object {a1: "abc", a2: "123", a3: "hello"}
script封装写法
function addScriptTag(src) {
var script = document.createElement('script');
script.setAttribute("type","text/javascript");
script.src = src;
document.body.appendChild(script);
}
window.onload = function () {
addScriptTag('http://example.com/ip?callback=foo');
}
function foo(data) {
console.log('Your public IP address is: ' + data.ip);
};
2. CORS
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
Example
使用如下接口 http://api.jirengu.com/city.php
<!DOCTYPE html>
<body>
<script>
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function(){
if (xhr.readyState === 4)
if (xhr.status === 200){
console.log(xhr.response)
}
}
xhr.open('get','http://api.jirengu.com/city.php')
xhr.send()
</script>
</body>
// 输出
长沙市
mock测试
<!DOCTYPE html>
<body>
<script>
var xhr = new XMLHttpRequest()
xhr.onreadystatechange = function(){
if (xhr.readyState === 4)
if (xhr.status === 200 || xhr.status === 304){
console.log(xhr.response)
}
}
xhr.open('get','http://localhost:8080/test2')
xhr.responseType = 'json'
xhr.send()
</script>
</body>
// 后端
router.get('/test2',function(req,res){
var cb = req.query.callback
var mockData = {
a1:'abc',
a2:'123',
a3:'hello'
}
console.log(res.header)
res.header('Access-Control-Allow-Origin','*')
res.send(mockData)
})
// 输出
Object {a1: "abc", a2: "123", a3: "hello"}
3. postMessage
HTML5引入了一个全新的API:跨文档通信 API(Cross-document messaging)。
这个API为window对象新增了一个window.postMessage
方法,允许跨窗口通信,不论这两个窗口是否同源。
举例来说,父窗口aaa.com向子窗口bbb.com发消息,调用postMessage
方法就可以了。
Example
// 父窗口代码
<!DOCTYPE html>
<body>
<button id='oaw'>open a window</button>
<button id='oai'>open a iframe</button>
<button id='cc'>change color</button>
<div>
</div>
<script>
var url = 'http://localhost:8080/index2.html'
var oaw = document.querySelector('#oaw')
var oai = document.querySelector('#oai')
var cc = document.querySelector('#cc')
var iframe = document.createElement('iframe')
var popuo
iframe.setAttribute('src',url)
oaw.addEventListener('click',function(){
popuo = window.open(url,'title')
}) // 打开一个新窗口
oai.addEventListener('click',function(){
document.querySelector('div').appendChild(iframe)
}) // 打开一个iframe
cc.addEventListener('click',function(e){
function random(min,max){
return Math.floor(min+(max-min)*Math.random());
} // 点击按钮时候改变子窗口颜色
var color = '#'+random(100,999)
if (popuo) popuo.postMessage(color,url)
if (iframe.contentWindow) iframe.contentWindow.postMessage(color,url)
})
window.addEventListener('message',function(e){ // 接收子窗口回传的data
document.body.style.background = e.data
})
</script>
</body>
// 子窗口代码
<!DOCTYPE html>
<style>
div {
background: yellow;
width: 100vw;
height: 100vh;
}
</style>
<body>
<div></div>
<script>
window.addEventListener('message',function(e){ // 接收父窗口发过来的data
document.querySelector('div').style.background = e.data
e.source.postMessage(e.data,'*') // 接收到的data发往父窗口
})
</script>
</body>
4. 片段识别符
片段标识符(fragment identifier)指的是,URL的#
号后面的部分,比如http://example.com/x.html#fragment
的#fragment
。如果只是改变片段标识符,页面不会重新刷新。
父窗口可以把信息,写入子窗口的片段标识符。
var src = originURL + '#' + data;
document.getElementById('myIFrame').src = src;
子窗口通过监听hashchange事件得到通知。
window.onhashchange = checkMessage;
function checkMessage() {
var message = window.location.hash;
// ...
}r
同样的,子窗口也可以改变父窗口的片段标识符。
parent.location.href= target + “#” + hash;
example
// 父页面
<!DOCTYPE html>
<body>
<button id='oai'>open a iframe</button>
<div>
</div>
<button id='curl'>change color</button>
<script>
var curl = document.querySelector('#curl')
var iframe = document.createElement('iframe')
var url = 'http://localhost:8080/index2.html'
iframe.setAttribute('src',url)
oai.addEventListener('click',function(){
document.querySelector('div').appendChild(iframe)
}) // 打开一个iframe
curl.addEventListener('click',function(e){
function random(min,max){
return Math.floor(min+(max-min)*Math.random());
} // 点击按钮时候改变子窗口颜色
var color = '#'+random(100,999)
iframe.src = url + color
})
</script>
</body>
// 子页面
<!DOCTYPE html>
<style>
div {
background: yellow;
width: 100vw;
height: 100vh;
}
</style>
<body>
<div></div>
<script>
window.onhashchange = checkMessage
function checkMessage(e){
document.querySelector('div').style.background = window.location.hash
}
</script>
</body>
两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值