JavaScript出于安全方面的考虑,不容许跨域调用其余页面的对象。那什么是跨域呢,简单地理解就是由于JavaScript同源策略的限制, a.com
域名下的js没法操做 b.com
或是 c.a.com
域名下的对象。javascript
当协议、子域名、主域名、端口号中任意一个不相同时,都算做不一样域。不一样域之间相互请求资源,就算做“跨域”。例如:http://www.abc.com/index.html 请求 http://www.efg.com/service.php。php
有一点必需要注意:跨域并非请求发不出去,请求能发出去,服务端能收到请求并正常返回结果,只是结果被浏览器拦截了。之因此会跨域,是由于受到了同源策略的限制,同源策略要求源相同才能正常进行通讯,即协议、域名、端口号都彻底一致。html
你们能够参照下图,有助于深刻理解跨域。前端
特别说明两点:java
第一:若是是协议和端口形成的跨域问题“前台”是无能为力的。web
第二:在跨域问题上,域仅仅是经过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”能够理解为“协议, 域名和端口必须匹配”。ajax
同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,若是缺乏了同源策略,则浏览器的正常功能可能都会受到影响。json
能够说Web是构建在同源策略基础之上的,浏览器只是针对同源策略的一种实现。跨域
同源策略限制从一个源加载的文档或脚本如何与来自另外一个源的资源进行交互。这是一个用于隔离潜在恶意文件的关键的安全机制。它的存在能够保护用户隐私信息,防止身份伪造等(读取Cookie)。浏览器
同源策略限制内容有:
Cookie、LocalStorage、IndexedDB 等存储性内容
DOM 节点
AJAX 请求不能发送
可是有三个标签是容许跨域加载资源:
<imgsrc=XXX>
<linkhref=XXX>
<scriptsrc=XXX>
接下来咱们讨论下有哪些处理跨域的方法。但全部的跨域都必须通过信息提供方的容许。若是未经容许便可获取,那是浏览器同源策略出现漏洞。
利用 <script>
元素的这个开放策略,网页能够获得从其余来源动态产生的 JSON 数据。JSONP请求必定须要对方的服务器作支持才能够。
JSONP和AJAX相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但AJAX属于同源策略,JSONP属于非同源策略(跨域请求)。
JSONP优势是兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具备局限性。
声明一个回调函数,其函数名(如fn)当作参数值,要传递给跨域请求数据的服务器,函数形参为要获取目标数据(服务器返回的data)。
建立一个 <script>
标签,把那个跨域的API数据接口地址,赋值给script的src,还要在这个地址中向服务器传递该函数名(能够经过问号传参 :?callback=fn
)。
服务器接收到请求后,须要进行特殊的处理:把传递进来的函数名和它须要给你的数据拼接成一个字符串,例如:传递进去的函数名是fn,它准备好的数据是 fn([{"name":"jianshu"}]
)。
最后服务器把准备的数据经过HTTP协议返回给客户端,客户端再调用执行以前声明的回调函数(fn),对返回的数据进行操做。
<script type="text/javascript">
function fn(data) {
alert(data.msg);
}
</script>
<script type="text/javascript" src="http://crossdomain.com/jsonServerResponse?jsonp=fn"></script>
其中 fn 是客户端注册的回调的函数,目的获取跨域服务器上的json数据后,对数据进行在处理。
最后服务器返回给客户端数据的格式为:
fn({ msg:'this is json data'})
JSONP都是GET和异步请求的,不存在其余的请求方式和同步请求,且jQuery默认就会给JSONP的请求清除缓存。
$.ajax({
url:"http://crossdomain.com/jsonServerResponse",
dataType:"jsonp",
type:"get",//能够省略
jsonpCallback:"fn",//->自定义传递给服务器的函数名,而不是使用jQuery自动生成的,可省略
jsonp:"jsonp",//->把传递函数名的那个形参callback变为jsonp,可省略
success:function (data){
console.log(data);}
});
整个CORS通讯过程,都是浏览器自动完成,不须要用户参与。对于开发者来讲,CORS通讯与同源的AJAX通讯没有差异,代码彻底同样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感受。所以,实现CORS通讯的关键是服务器。只要服务器实现了CORS接口,就能够跨源通讯。
CORS要求浏览器(>IE10)和服务器的同时支持,是跨域的根本解决方法,由浏览器自动完成。
优势在于功能更增强大支持各类HTTP Method,缺点是兼容性不如JSONP。
只须要在服务器端作一些小小的改造便可:
header("Access-Control-Allow-Origin:*");
header("Access-Control-Allow-Methods:POST,GET");
例如:网站 http://localhost:63342/
页面要请求 http://localhost:3000/users/userlist
页面,userlist页面返回json字符串格 {name:'Mr.Cao',gender:'male',career:'IT Education'}
:
//在服务器端设置同源策略地址
router.get("/userlist", function (req, res, next) {
var user = {name: 'Mr.Cao', gender: 'male', career: 'IT Education'};
res.writeHeader(200,{"Access-Control-Allow-Origin":'http://localhost:63342'});
res.write(JSON.stringify(user));
res.end();
});
在响应头上添加 Access-Control-Allow-Origin
属性,指定同源策略的地址。同源策略默认地址是网页的自己。只要浏览器检测到响应头带上了CORS,而且容许的源包括了本网站,那么就不会拦截请求响应。
Websocket是HTML5的一个持久化的协议,它实现了浏览器与服务器的全双工通讯,同时也是跨域的一种解决方案。WebSocket和HTTP都是应用层协议,都基于 TCP 协议。可是 WebSocket 是一种双向通讯协议,在创建链接以后,WebSocket 的 server 与 client 都能主动向对方发送或接收数据。同时,WebSocket 在创建链接时须要借助 HTTP 协议,链接创建好了以后 client 与 server 之间的双向通讯就与 HTTP 无关了。
原生WebSocket API使用起来不太方便,咱们使用Socket.io,它很好地封装了webSocket接口,提供了更简单、灵活的接口,也对不支持webSocket的浏览器提供了向下兼容。
//前端代码:
<div>user input:<input type="text"></div>
<script src="./socket.io.js"></script>
<script>
var socket = io('http://www.domain2.com:8080');
// 链接成功处理
socket.on('connect', function() {
// 监听服务端消息
socket.on('message', function(msg) {
console.log('data from server: ---> ' + msg);
});
// 监听服务端关闭
socket.on('disconnect', function() {
console.log('Server socket has closed.');
});
});
document.getElementsByTagName('input')[0].onblur = function() {
socket.send(this.value);
};
</script>
//Nodejs socket后台:
var http = require('http');
var socket = require('socket.io');
// 启http服务
var server = http.createServer(function(req, res) {
res.writeHead(200, {
'Content-type': 'text/html'
});
res.end();
});
server.listen('8080');
console.log('Server is running at port 8080...');
// 监听socket链接
socket.listen(server).on('connection', function(client) {
// 接收信息
client.on('message', function(msg) {
client.send('hello:' + msg);
console.log('data from client: ---> ' + msg);
});
// 断开处理
client.on('disconnect', function() {
console.log('Client socket has closed.');
});
});
若是两个网页不一样源,就没法拿到对方的DOM。典型的例子是iframe窗口和 window.open
方法打开的窗口,它们与父窗口没法通讯。HTML5为了解决这个问题,引入了一个全新的API:跨文档通讯 API(Cross-document messaging)。这个API为window对象新增了一个 window.postMessage
方法,容许跨窗口通讯,不论这两个窗口是否同源。
postMessage方法的第一个参数是具体的信息内容,第二个参数是接收消息的窗口的源(origin),即"协议 + 域名 + 端口"。也能够设为 *
,表示不限制域名,向全部窗口发送。
接下来咱们看个例子: http://localhost:63342/index.html
页面向 http://localhost:3000/message.html
传递“跨域请求信息”
//发送信息页面 http://localhost:63342/index.html
<html lang="en">
<head>
<meta charset="UTF-8">
<title>跨域请求</title>
</head>
<body>
<iframe src="http://localhost:3000/users/reg" id="frm"></iframe>
<input type="button" value="OK" onclick="run()">
</body>
</html>
<script>
function run(){
var frm=document.getElementById("frm");
frm.contentWindow.postMessage("跨域请求信息","http://localhost:3000");
}
</script>
//接收信息页面 http://localhost:3000/message.html
window.addEventListener("message",function(e){ //经过监听message事件,能够监听对方发送的消息。
console.log(e.data);
},false);