一、 跨域请求的含义
浏览器的同源策略,出于防范跨站脚本的攻击,禁止客户端脚本(如 JavaScript)对不同域的服务进行跨站调用。 一般的,只要网站的 协议名protocol、 主机host、 端口号port 这三个中的任意一个不同,网站间的数据请求与传输便构成了跨域调用。
二、 利用 JSONP 实现跨域调用
说到跨域调用,可能大家首先想到的或者听说过的就是 JSONP 了。
JSONP 是 JSON 的一种使用模式,可以解决主流浏览器的跨域数据访问问题。其原理是根据 XmlHttpRequest 对象受到同源策略的影响,而
1、使用 jQuery 集成的 $.ajax 实现 JSONP 跨域调用:
// 回调函数
function jsonpCallback(data) {}
$("#submit").click(function() {
$.ajax({
url: 'http://localhost:3001/ajax/api',
data: {},
dataType: 'jsonp',
cache: false,
timeout: 5000,
// jsonp 字段含义为服务器通过什么字段获取回调函数的名称
jsonp: 'callback',
// 声明本地回调函数的名称,jquery 默认随机生成一个函数名称
jsonpCallback: 'jsonpCallback',
success: function(data) {},
error: function(jqXHR, textStatus, errorThrown) {}
});
});
2、使用
function jsonpCallback(data) {}
<script src='http://localhost:3001/ajax/api?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032'></script>
function jsonpCallback(data) {}
<script src='http://localhost:3001/ajax/api?callback=jsonpCallback&name=chiaki&id=3001&_=1473164876032'></script>
三、 使用 CORS 实现跨域调用
3.1 什么是 CORS?
Cross-Origin Resource Sharing(CORS)跨域资源共享是一份浏览器技术的规范,提供了 Web 服务从不同域传来沙盒脚本的方法,以避开浏览器的同源策略,是 JSONP 模式的现代版。与 JSONP 不同,CORS 除了 GET 要求方法以外也支持其他的 HTTP 请求。用 CORS 可以让网页设计师用一般的 XMLHttpRequest,这种方式的错误处理比 JSONP 要来的好。另一方面,JSONP 可以在不支持 CORS 的老旧浏览器上运作。现代的浏览器都支持 CORS。
3.2 CORS 的实现
app.post('/cors', function(req, res) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "X-Requested-With");
res.header("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");
res.header("X-Powered-By", ' 3.2.1')
res.header("Content-Type", "application/json;charset=utf-8");
var data = {
name: req.body.name + ' - server 3001 cors process',
id: req.body.id + ' - server 3001 cors process'
}
console.log(data)
res.send(data)
res.end()
})
// express框架
app.all('*', function(req, res, next) {
res.append('Access-Control-Allow-Origin', '*');
next()
});
四、 一些其它的跨域调用方式
4.1 window.name
window对象有个name属性,该属性有个特征:即在一个窗口 (window) 的生命周期内,窗口载入的所有的页面都是共享一个 window.name 的,每个页面对 window.name 都有读写的权限,window.name 是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。
4.2 window.postMessage()
这个方法是 HTML5 的一个新特性,可以用来向其他所有的 window 对象发送消息。需要注意的是我们必须要保证所有的脚本执行完才发送 MessageEvent,如果在函数执行的过程中调用了他,就会让后面的函数超时无法执行。
4.3 通过document.domain跨域
修改document.domain的方法只适用于不同子域的框架间的交互。(iframe) www.damonare.cn/a.html damonare.cn/b.html
document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。
(1) 在页面www.damonare.cn/a.html 中设置document.domain:
<iframe id = "iframe" src="http://damonare.cn/b.html" onload = "test()"></iframe>
<script type="text/javascript">
document.domain = 'damonare.cn';//设置成主域
function test(){
alert(document.getElementById('#iframe').contentWindow);//contentWindow 可取得子窗口的 window 对象
}
</script>
(2) 在页面damonare.cn/b.html 中也设置document.domain:
<script type="text/javascript">
document.domain = 'damonare.cn';// 在iframe载入这个页面也设置document.domain,使之与主页面的document.domain相同
</script>
4.4 通过location.hash跨域
因为父窗口可以对iframe进行URL读写,iframe也可以读写父窗口的URL,URL有一部分被称为hash,就是#号及其后面的字符,它一般用于浏览器锚点定位,Server端并不关心这部分,应该说HTTP请求过程中不会携带hash,所以这部分的修改不会产生HTTP请求,但是会产生浏览器历史记录。
此方法的原理就是改变URL的hash部分来进行双向通信。每个window通过改变其他 window的location来发送消息(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于父窗口域名下的一个代理iframe),并通过监听自己的URL的变化来接收消息。这个方式的通信会造成一些不必要的浏览器历史记录,而且有些浏览器不支持onhashchange事件,需要轮询来获知URL的改变,最后,这样做也存在缺点,诸如数据直接暴露在了url中,数据容量和类型都有限等。