跨域的几种方式

什么是跨域?

跨域:就是不同域之间进行相互资源请求;

例如:http://www.test.com/index.com  请求  http://www.test01.com/server.php

即进行不同的域名下的资源调用。

注意:域名对应的IP地址也算是跨域操作;例:127.0.0.1和localhost虽然对应,但在地址栏中算两个域。

为什么出现跨域? 

浏览器在解析JavaScript出于安全方面的考虑,只允许在同域名下页面进行相互资源请求调用,不允许调用其他域名下的页面的对象;简单的理解就是因为JavaScript同源策略的限制。

注意:跨域并不是请求发不出去,请求能发出去,服务器能收到请求并正常返回结果,只是结果被浏览器拦截了,所以页面无法正常使用数据。

什么是同源策略?

同源策略要求源相同才能进行正常的资源交互,即要求当前页面与调用资源的协议,域名、子域名、端口完全一致;不一致则就是跨域。

一个域名地址的组成:

参考如下图理解:

说明:

1、如果是协议和端口造成的跨域问题“前台”是无能为力的。

2、在跨域问题上,域仅仅是通过“URL的首部”来识别而不会根据域名对应的IP地址是否相同来判断。“URL的首部”可以理解为“协议, 域名和端口必须匹配”。

 同源策略的限制

同源策略限制一个资源地址加载的文档或脚本与来自另一个资源地址的资源进行交互。这是浏览器的一个用于隔离潜在恶意文件的关键的安全机制。它的存在可以保护用户隐私信息,防止身份伪造等(读取Cookie)。

同源策略限制内容有:

1、Cookie、LocalStorage、IndexedDB等存储性内容

2、不允许进行DOM节点的操作

3、不能进行AJAX请求

同源策略的天然支持跨域请求的特性属性

1、<img  src="xxx" />

2、<link  href="xxx" />

3、<script  src="xxx" ></script>

解决同源策略的方法

方法一、处理跨域的jsonp方法

JSONP原理

利用<script  src="xxx">元素的这个天然支持跨域的策略,网页可以得到从其他来源动态产生的 JSON 数据。JSONP请求一定需要对方的服务器做支持才可以。

JSONP和AJAX对比

JSONP和Ajax相同,都是客户端向服务器端发送请求,从服务器端获取数据的方式。但Ajax属于同源策略,JSONP属于非同源策略(跨域请求)。

JSONP优缺点

JSONP优点是兼容性好,可用于解决主流浏览器的跨域数据访问的问题。缺点是仅支持get方法具有局限性。

 

JSONP的流程(以第三方API地址为例,不必考虑后台程序)

声明一个回调函数,其函数名(如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">
其中 fn 是客户端注册的回调的函数,目的获取跨域服务器上的json数据后,对数据进行在处理。

最后服务器返回给客户端数据的格式为:

fn({ msg:'this  is  json  data'})
jQuery的jsonp形式

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原理

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现CORS通信的关键是服务器。只要服务器实现了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,并且允许的源包括了本网站,那么就不会拦截请求响应。

header("Access-Control-Allow-Origin:*");  
//    *  :表示所有其他的域可以向当前域发送请求
 
//或者
 
header("Access-Control-Allow-Origin:http://test.com:80(相同默认不写)");    
//  http://test.com:80 表示指定具体的这个域可以向当前域发送请求。
//当然也可以指定多个特定域名,多个地址的话用逗号分隔即可。
方法三:WebSocket

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.');     
    });
});
方法四:postMessage

如果两个网页不同源,就无法拿到对方的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" οnclick="run()">  
</body>  
</html>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值