利用JSONP解决跨域问题

什么是跨域?

简单的来说,出于安全方面的考虑,javascript不能访问其他服务器上的内容,即“同源策略”(参考1参考2)。跨域就是通过某种手段绕过同源策略去访问不同服务器上的内容。只要域名、端口、协议任何一个不同,就是不同的域。协议或端口不同只能通过后端来解决。

URL 说明 是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js 同一域名下 允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js 同一域名下不同文件夹 允许
http://www.a.com:8000/a.js
http://www.a.com/b.js 同一域名,不同端口 不允许
http://www.a.com/a.js
https://www.a.com/b.js 同一域名,不同协议 不允许
http://www.a.com/a.js
http://70.32.92.74/b.js 域名和域名对应ip 不允许
http://www.a.com/a.js
http://script.a.com/b.js 主域相同,子域不同 不允许
http://www.a.com/a.js
http://a.com/b.js 同一域名,不同二级域名(同上) 不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js 不同域名 不允许

解决跨域问题的方案有很多,最流行的就是jsonp了,但是jsonp只能解决域名不同造成的跨域,端口、协议不同的跨域可以通过后端方案解决。下面分析下各种解决方案吧。

JSONP

JSON(Javascript Object Notation)是一种轻量级数据格式,JSONP(Json for padding)是JSON 的一种“使用模式”,可以让网页从别的网域要资料。
JSONP也叫填充式JSON,是应用JSON的一种新方法,只不过是被包含在函数调用中的JSON,例如:

callback({a:’b’});

JSONP由两部分组成:回调函数和数据。回调函数是当响应到来时应该在页面中调用的函数,而数据就是传入回调函数中的JSON数据。

JSONP跨域原理

在同源策略下,在某个服务器下的页面是无法获取到该服务器以外的数据的,当我们正常地请求一个JSON数据的时候,服务端返回的是一串JSON类型的数据,而我们使用JSONP模式来请求数据的时候,服务端返回的是一段可执行的JavaScript代码。

img、iframe、script等标签是个例外,这些标签可以通过src属性请求到其他服务器上的数据。利用script标签的开放策略,我们可以实现跨域请求数据,当然,也需要服务端的配合。

在jQuery中使用JSONP获取跨域数据

jQuery代码

$(document).ready(function(){
    $.ajax({
    url : 'http://b.test:8080/jsonp.php',
    type : 'post',
    dataType : 'jsonp',
    jsonpCallback: 'hehe',
    success : function (data) {
        alert(data.a);
    },
    error : function(data) {}
    });
});

PHP代码


<?php
$jsondata = json_encode(array(‘a’ =&gt; ‘b’));
$callback = $_REQUEST[‘callback’];
echo “(function(){var _jsonData=$jsondata; $callback(_jsonData);})()”;

1、url 中不用指定 callback 参数。对于 jQuery 中的 jsonp 来说,callback 参数是自动添加的
2、默认情况下,jQuery 生成的 jsonp 请求中 callback 参数是形如 callback=jQuery180099599698651582_1393992892572 这种根据看似随机的名字,对应的就是 success 那个处理函数,所以一般不用特意处理。
3、如果响应内容中是写死了 callback 名的话,那么可以对 jQuery 的 jsonp 指定 callback 名。

JSONP的应用

JSONP在开放API中可以起到非常重要的作用,开放API一般是运用于开发者的应用上,而这些应用往往是在开发者的服务器上而并非在新浪微博的服务器上,因此跨域请求数据成为前端开发者们所需要解决的一大问题,广大开放平台应该实现对JSONP的支持,这一点新浪微博开放平台便做的非常好(虽然某些API里没有说明,但实际上是可以使用JSONP方式调用的)。

JSONP的优缺点

优点:
1、相比XMLHttpRequest不受同源策略的限制;
2、支持古老的浏览器。

缺点:
1、它只支持GET请求而不支持POST等其它类型的HTTP请求;
2、它只支持跨域HTTP请求这种情况,不能解决不同域的两个页面之间如何进行JavaScript调用的问题。
参考1:http://www.clanfei.com/2012/08/1637.html
参考2:https://segmentfault.com/q/1010000000424040

CORS(Cross-Origin-Resource-Shares)跨域资源共享

解决跨域问题,也可以在后端服务器直接设置header内容Access-Contrl-Allow-Origin

PHP代码可以这样写:

<?php
header('Access-Control-Allow-Origin: '.$_SERVER['HTTP_ORIGIN']);
header('Access-Control-Allow-Methods: POST, GET, OPTIONS');
header('Access-Control-Max-Age: 1000');
header('Access-Control-Allow-Headers: Content-Type');

Apache配置方法:

Header set Access-Control-Allow-Origin *  

以上配置的含义是允许所有的域发起的请求都可以获取该服务器上的资源,当然这样的配置有很大的安全问题,很容易遭受XSS(跨站脚本攻击)。可以只允许某个域访问我们的服务器,如下设置:

Header set Access-Control-Allow-Origin http://www.sundabao.com/

对于通配符*,它可以直接Access-Control-Allow-Origin:*这样使用,但它是不允许通配子域名的,如:Access-Control-Allow-Origin:*.sundabao.com。

解决跨域问题的方案还有很多种,常用的有以下几种:

前端解决方案

1、JSONP
2、Iframe
参考:http://liuwanlin.info/shi-shi-kua-yu-tong-xin-iframe/

后端解决方案

1、反向代理
参考:http://wenzhixin.net.cn/2014/06/05/apache_proxy
2、CORS跨域资源共享
参考1:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

关于跨域问题的讨论:
参考1:https://segmentfault.com/a/1190000000718840
参考2:https://www.zhihu.com/question/19618769

JackSun

JackSun

I'm a coder.

You may also like...

1 Response

  1. 齐天大屌 says:

    学习了

Leave a Reply

Your email address will not be published.