一. 通过JSONP跨域
利用script标签不受同源策略的影响的特性,在页面中动态插入script标签。script标签的src地址就是后端api接口地址,并以GET的方式将前端回调处理函数的名称告诉后端。后端收到这个请求以后,会将数据放在回调函数的参数位置返回。
由于<script>元素请求的脚本直接作为代码运行。这时,只要浏览器定义了这个回调函数,该函数就会立即调用。
index.html
<head>
<meta charset="UTF-8">
<title>JSON 跨域</title>
<script type='text/javascript'>
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://localhost:8080?callback=foo')
}
function foo(data) {
console.log(data.name+ '的淘气值是:' + data.naughty)
}
</script>
</head>
<body>
</body>
node.js
var http = require('http');
var url = require('url');
var server = http.createServer(function(req, res) {
var pathObj = url.parse(req.url, true);
var data = {"name": "jack", "naughty": "49"};
console.log(pathObj)
var script = pathObj.search.split('=')[1] + '(' + JSON.stringify(data) + ')';
res.write(script);
res.end();
}).listen(8080)
console.log('visit http://localhost:8080')
二. postMessage
HTML5引入了一个全新的API:跨文档通信 API(Cross-document messaging),这个 API 为window对象新增了一个window.postMessage方法,允许跨窗口通信,不论这两个窗口是否同源。举例来说,父窗口aaa.com向子窗口bbb.com发消息,调用postMessage方法就可以了。
parent.html
<head>
<meta charset="UTF-8">
<title>parent</title>
<script type="text/javascript">
function sendIt() {
//send message by postMessage
var otherWindow = document.querySelector('#otherPage').contentWindow;
var msg = document.querySelector('#message').value;
otherWindow.postMessage(msg, 'http://bbb.com:8080')
}
</script>
</head>
<body>
<iframe src="http://bbb.com:8080/child.html" frameborder="1" id="otherPage"></iframe>
<br />
<input type="text" id="message">
<input type="button" value="send to child" onclick="sendIt()">
</body>
child.html
<head>
<meta charset="UTF-8">
<title>child</title>
<script type="text/javascript">
window.addEventListener('message', function(event){
document.querySelector('#content').innerHTML += event.data
}, false)
</script>
</head>
<body>
<p>Webpage from aaa.com</p>
<div id="content"></div>
</body>
三. CORS
CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能。整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。。对于开发者来说,CORS 通信与普通的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感知。因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨域通信。
CORS 请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。
以下一简单请求为例:
浏览器发现这次跨域 AJAX 请求是简单请求,就自动在头信息之中,添加一个Origin字段。服务器回应的头信息Access-Control-Allow-Origin指定的Origin如果包含请求的Origin就可以完成跨域,否则会抛出错误。
index.html
<head>
<meta charset="UTF-8">
<title>CORS跨域</title>
</head>
<body>
<div class="value"><p>这里显示结果</p></div>
<button class="search">查询淘气值</button>
<script type="text/javascript">
function $(selector) {
return document.querySelector(selector)
}
$('.search').addEventListener('click', function(){
var xhr = new XMLHttpRequest()
xhr.open('GET', 'http://localhost:8080/naughty', true)
xhr.send()
xhr.onload = function(){
appendHTML(JSON.parse(xhr.responseText))
}
})
function appendHTML(data){
var html = '';
html += '<p>' + data.name +'的淘气值是:' + data.naughty + '</p>';
$('.value').innerHTML = html;
}
</script>
</body>
server.js
ar http = require('http');
var fs = require('fs');
var path = require('path');
var url = require('url');
http.createServer(function(req, res) {
var pathObj = url.parse(req.url, true);
console.log(pathObj.pathname)
switch (pathObj.pathname){
case '/naughty':
var data = {name: "jack", naughty: 49}
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:8080')
res.end(JSON.stringify(data))
break;
default:
fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
if(e){
res.writeHead(404,'not found')
res.end('<h1>404 NOT FOUND</h1>')
}else {
res.end(data)
}
})
}
}).listen(8080)
console.log('visit http://localhost:8080')
四. 降域
如果两个页面的origin有相似的部分,可以指定他们的document.domain为同一个origin。那么这两个不同源的页面就实现了跨域共享。
a.html
<head>
<meta charset="UTF-8">
<title>main page</title>
<style>
.ct {
width: 910px;
margin: auto;
}
.main {
float: left;
width: 450px;
height: 300px;
border: 1px solid #ddd;
}
.main input {
margin: 20px;
width: 200px;
}
iframe {
float: right;
width: 450px;
height: 300px;
border: 1px dashed #ddd;
}
</style>
</head>
<body>
<div class="ct">
<h1>使用降域实现跨域</h1>
<div class="main">
<input type="text" placeholder="http://a.jp.com:8080/a.html">
</div>
<iframe src="http://b.jp.com:8080/b.html" frameborder="0"></iframe>
<script>
document.querySelector('.main input').addEventListener('input', function(){
console.log(this.value);
window.frames[0].document.querySelector('input').value = this.value;
})
document.domain = "jp.com"
</script>
</div>
</body>
b.html
<meta charset="UTF-8">
<title>other page</title>
<style>
html, body {
margin: 0;
}
input {
margin: 20px;
width: 200px;
}
</style>
</head>
<body>
<input type="text" id="input" placeholder="http://b.jp.com:8080/b.html">
<script>
document.querySelector('#input').addEventListener('input', function(){
window.parent.document.querySelector('input').value = this.value;
})
document.domain = "jp.com";
</script>
</body>