跨域解决方案介绍2,转自github.

跨域问题

浏览器的安全基石是“同源政策”,所谓同源是指协议相同,域名相同,端口相同,只要其中有一个不同,则称为不同源。不同源的网站之间不能够相互请求数据,以确保用户数据的安全性。 但有的时候,一个网站不得不请求别的域上面的数据,这个过程就称为跨域。

跨域的实现方法有以下几种:

(1)JSONP

JSONP(JSON with padding)的原理是script标签不受同源安全策略限制,它可以向别的域发送get请求。

function handleResponse(data) {
	console.log('The response data is:' + data);
}
//动态添加script标签
var script = document.createElement('script');
script.src = 'http://www.baidu.com/json?callback=handleResponse';
script.setAttribute('type', 'text/javascript');
document.body.appendChild(script);

后台收到get请求后,根据callback参数生成相应的JSONP数据 handleResponse({'data': serverdata}),这段数据返回前端就会被当作js代码执行,触发回调函数。

jQuery和JSONP

$(document).ready(function(){
	$.ajax({
		type: 'get',
		async: false,
		// 查询CA1998次航班的信息
		url: 'http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998',
		dataType: 'jsonp',
		//传递给请求处理程序或页面的,用以获得jsonp回调函数名的参数名(一般默认为:callback)
		jsonp: 'callback',
		//自定义的jsonp回调函数名称,默认为jQuery自动生成的随机函数名,也可以写"?",jQuery会自动为你处理数据
		jsonpCallback: 'flightHandler',
		success: (json) => {
			alert('您查询到航班信息:票价: ' + json.price + ' 元,余票: ' + json.tickets + ' 张。');
		},
		error: () => {
			alert('fail');
		}
	});
});

(2)CORS

CORS是一个W3C标准,全称为跨域资源共享(cross-origin resource sharing),它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

整个CORS通信过程都由浏览器自动完成,用户不需要参与,对于前端开发者来说,同源ajax和CORS的代码完全相同,因此,实现CORS的关键在于服务器是否提供CORS接口。

简单请求例子:

GET /cors HTTP/1.1
Origin: http://api.bob.com
Host: api.alice.com
Accept-Language: en-US
Connection: keep-alive
User-Agent: Mozilla/5.0...

若服务器允许来自http://api.bob.com的跨域请求,则会进行如下响应:

Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Credentials: true  //是否允许发送cookie
Access-Control-Expose-Headers: FooBar  // 额外的header字段
Content-Type: text/html; charset=utf-8

若不允许,则不会设置Access-Control-Allow-Origin字段,如果服务器将此字段设为*,则表示服务器接受所有域的跨域请求。

Access-Control-Allow-Credentials: true 则表明服务器接受cookie,同时开发者应在AJAX打开withCredentials属性,以允许浏览器发送cookie:

var xhr = new XMLHttpRequest();
xhr.withCredentials = true;

跨域资源共享 CORS 详解

(3)iframe + HTML5 postMessage

即不同window间通过HTML5的API postMessage进行跨域通信,其格式为:

otherWindow.postMessage(data, targetOrigin);
// otherWindow指要接收消息的窗口,targetOrigin限制接收窗口所在的域,若不想限制,设为*即可

示例:

<!--a.com/index.html-->
<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {
    var ifr = document.getElementById('ifr');
    var targetOrigin = 'http://b.com';  // 若写成'http://b.com/c/proxy.html'效果一样
                                        // 若写成'http://c.com'就不会执行postMessage了
    ifr.contentWindow.postMessage('Message from a.com!', targetOrigin);
};
</script>
<!--b.com/index.html-->
<script type="text/javascript">
    window.addEventListener('message', function(event){
        // 通过origin属性判断消息来源地址
        if (event.origin == 'http://a.com') {
            alert(event.data);    // 弹出"Message from a.com!"
            alert(event.source);  // 对a.com、index.html中window对象的引用
                                  // 但由于同源策略,这里event.source不可以访问window对象
        }
    }, false);
</script>

(4)iframe + window.name

原理: windoe.name 的值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的 name 值(2MB)

a.com/1.html

<script type="text/javascript">
function getData() {
	var ifr = document.getElementById('proxy');
	ifr.src = 'a.com/2.html'; //跳转到同源网站
	ifr.onLoad = function() {
		var data = ifr.contentWindow.name;
		alert(data);
	}
}
</script>
<iframe src='http://other-origin/data.html' style='display:none' onLoad='getData()'></iframe>

other-origin/data.html

var data = {
	name: 'xiaoming',
	age: 12
};
window.name = JSON.stringify(data);

(5)WebSocket

WebSocket是一种通信协议,使用ws://(非加密)和wss://(加密)作为协议前缀。该协议不实行同源政策,只要服务器支持,就可以通过它进行跨源通信。

请求头信息:(多了个 origin)
GET /chat HTTP/1.1
Host: server.example.com
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: x3JJHMbDL1EzLkh9GBhXDw==
Sec-WebSocket-Protocol: chat, superchat
Sec-WebSocket-Version: 13
Origin: http://example.com

响应头:(如果origin在白名单内)
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: HSmrc0sMlYUkAGmm5OPpG2HaGWk=
Sec-WebSocket-Protocol: chat

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏jeremy的技术点滴

Web跨域总结

3347
来自专栏乐沙弥的世界

linux 6下编译安装配置LAMP平台

1232
来自专栏静默虚空的博客

Elastic 技术栈之 Filebeat

Elastic 技术栈之 Filebeat 简介 Beats 是安装在服务器上的数据中转代理。 Beats 可以将数据直接传输到 Elasticsearch 或...

5047
来自专栏梦里茶室

java后台开发- NOTE

2015-1-6: IDEA servlet-api.jar    idea从14升级到15后,发现 import javax.servlet.AsyncCon...

2289
来自专栏jeremy的技术点滴

boot2docker中安装docker-compose

3444
来自专栏PHP在线

什么是CGI、FastCGI、PHP-CGI、PHP-FPM、Spawn-FCGI?

什么是CGI CGI全称是“公共网关接口”(Common Gateway Interface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种...

4969
来自专栏后端技术探索

nginx服务器究竟是怎么执行php项目

CGI全称是“公共网关接口”(Common Gateway Interface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网...

3081
来自专栏企鹅号快讯

Python3爬取B站视频弹幕文字+视频

需要准备的环境: 1、一个B站账号,需要先登录,否则不能查看历史弹幕记录 2、联网的电脑和顺手的浏览器,我用的Chrome 3、Python3环境以及reque...

3119
来自专栏pangguoming

Mongodb集群搭建的三种方式

 Mongodb是时下流行的NoSql数据库,它的存储方式是文档式存储,并不是Key-Value形式。关于Mongodb的特点,这里就不多介绍了,大家可以去看看...

4259
来自专栏派森公园

docker的reap问题

在使用docker容器的时候,应该了解“PID1僵尸进程reap”问题。如果使用的时候不加注意,可能会导致出现一些意想不到的问题。

1373

扫码关注云+社区

领取腾讯云代金券