通过XMLHttpRequest(XMR) 实现的Ajax 通信的一个主要限制就是跨域问题。默认情况下,XHR 对象只能访问与包含它的页面位于同一个域中的资源。
1,CORS 跨资源共享
CORS(Cross-Origin Resource Sharing 跨资源共享)解决了AJAX 跨域的问题。
跨域资源共享(CORS )是一种网络浏览器的技术规范,它为Web服务器定义了一种方式,允许网页从不同的域访问其资源。而这种访问是被同源策略所禁止的。
CORS 通过使用自定义的 HTTP 头部让浏览器与服务器沟通,从而决定请求或相应是成功还是失败。
实现此功能非常简单,只需由服务器发送一个响应标头即可。假设 http://www.b.com 页面打算从 http://www.s.com 请求提取数据。如果直接用 AJAX 请求会返回“源不匹配”的错误,即跨域不允许。
利用 CORS, http://www.s.com 域要在被请求的php脚本头部添加
header(“Access-Control-Allow-Origin:http://www.b.com“); 就可以允许来自 http://www.b.com 的请求。
“*”号表示允许任何域向我们的服务端提交请求:
header(“Access-Control-Allow-Origin:*“);
不依赖XHR 对象,而是利用 DOM 中能够执行跨域请求的功能,也可以实现跨域通信。比如下面的 图像 Ping 和JSONP。
2,图像 Ping
一个网页可以再任何网页中加载图片,不用担心跨域问题,图片不受“同源策略”限制。这也是在线广告跟踪浏览量的主要方式。
缺点:只能发送GET 请求;无法访问服务器的响应文本。因此只能用于浏览器与服务器的单向通信。
3,JSONP
JSONP 看起来与JSON 差不多,只不过是被包含在函数调用中的JSONcallback({"name":"Nike"});
.
从上面也可以看出,JSONP由回调函数和数据两部分组成。回调函数是当响应到来时应该在页面中调用的函数。回调函数是响应到来时应该在页面中调用的函数,而数据是传入回调函数中的JSON数据(服务器填充的)。
看到这里对JSONP的解释,清楚了很多:
1, web页面也可以执行跨域的 js 文件。
远程服务器remoteserver.com根目录下有个remote.js文件代码如下:
alert('我是远程文件');
本地服务器localserver.com下有个jsonp.html页面代码如下:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
</head>
<body>
</body>
</html>
毫无疑问,页面将会弹出一个提示窗体,显示跨域调用成功。
2,现在我们在jsonp.html页面定义一个函数,然后在远程remote.js中传入数据进行调用。
jsonp.html 页面:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
var localHandler = function(data){
alert('我是本地函数,可以被跨域的remote.js文件调用,远程js带来的数据是:' + data.result);
};
</script>
<script type="text/javascript" src="http://remoteserver.com/remote.js"></script>
</head>
<body>
</body>
</html>
remote.js文件代码如下:
localHandler({"result":"我是远程js带来的数据"});
localHandler 是请求页面中的函数,上面的代码相当于把一个JSON数据{"result":"我是远程js带来的数据"}
通过函数localHandler (jsonp页面)的调用传入。
最后页面弹出窗口,正确显示。
但是又一个问题出现了,怎么让远程js知道它应该调用的本地函数叫什么名字呢?毕竟是jsonp的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同。
3,只要服务端提供的 js 脚本是动态生成的就可以了
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title></title>
<script type="text/javascript">
// 得到航班信息查询结果后的回调函数
var flightHandler = function(data){
alert('你查询的航班结果是:票价 ' + data.price + ' 元,' + '余票 ' + data.tickets + ' 张。');
};
// 提供jsonp服务的url地址(不管是什么类型的地址,最终生成的返回值都是一段javascript代码)
var url = "http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler";
// 创建script标签,设置其属性
var script = document.createElement('script');
script.setAttribute('src', url);
// 把script标签加入head,此时调用开始
document.getElementsByTagName('head')[0].appendChild(script);
</script>
</head>
<body>
</body>
</html>
到调用的url中传递了一个code参数,告诉服务器我要查的是CA1998次航班的信息,而callback参数则告诉服务器,本地回调函数叫做flightHandler,所以请把查询结果传入这个函数中进行调用。
服务器很聪明,这个叫做flightResult.aspx的页面生成了一段这样的代码提供给jsonp.html
flightHandler({
"code": "CA1998",
"price": 1780,
"tickets": 5
});
3,JSONP 与 Ajax 异同
- 目的相同,都是请求一个url,将服务器返回的数据进行处理。因此jquery和ext等框架都把jsonp作为ajax的一种形式进行了封装;
2. 但是Ajax 是通过XMLHttpRequest 获取非本页面的内容,jsonp 是通过动态添加<script>
标签来调用服务器提供的 js 脚本.
参考:
http://www.web-fish.com/program/php/794.html;
http://www.bestphper.cn/article-283.html
http://www.cnblogs.com/dowinning/archive/2012/04/19/json-jsonp-jquery.html#top