欢迎关注我的个人博客分享一些前端技术、面试题、面试技巧等
说到 AJAX 就会不可避免的面临两个问题。
- AJAX 以何种格式来交换数据?
- 跨域的需求如何解决?
在这里总结了解决跨域问题的几种方法
- Flash
- 服务器代理中转
- JSONP
- document.domain(针对基础域名相同的情况)
但到目前为止最推崇或者说是首选的方案还是用JSON 来传数据,靠 JSONP 来跨域。
JSON 和 JSONP 虽然只有一个字母的差别,但其实他们根本不是一回事。
- JSON是一种轻量级的数据交换格式
- JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议,是JSON的一种“使用模式”,可用于解决主流浏览器的跨域数据访问的问题
- 一个是描述信息的格式,一个是信息传递双方约定的方法
什么是 JSON
JSON 是 JavaScript Object Notation 的缩写,它是一种数据交换格式。在 JSON 中,一共有 6 种数据类型:Number,Boolean,String,Null,Array,Object以及这些数据类型的任意组合。
由于 JSON 非常简单,很快就风靡 Web 世界,并且成为 ECMA 标准。几乎所有编程语言都有解析 JSON 的库,而在 JavaScript 中,我们可以直接使用 JSON,因为 JavaScript 内置了 JSON 的解析。
什么是 JSONP
JSONP 原理
- Web 页面上用
<script>引入 js 文件时不受是否跨域的影响(不仅如此,我们还发现凡是拥有 "src" 这个属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>) - 于是我们把数据放在服务器上,并且数据为 JSON 格式(因为 JS 可以轻松处理 JSON 数据)
- 因为我们无法监控通过
<script>的src属性是否把数据获取完成,所以我们需要做一个处理。 - 实现定义好处理跨域获取数据的函数
- 用
src获取数据的时候添加一个参数cb = 'callback'(服务端或根据参数cb的值返回对应的内容),此内容以cb对应的值callback为函数真实要传递的数据为函数的参数的一串字符
JSONP 的客户端具体实现
1> 我们知道,哪怕跨域 js 文件中的代码,web 页面也是可以无条件执行的。
远程服务器server.com根目录下有个server.js文件代码如下:
alert("我是远程文件");
本地服务器local.com下有个jsonp.html页面代码如下:
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/script" src="http://server.com/server.js"></script>
</head>
<body></body>
</html>
毫无疑问,页面将会弹出一个提示窗体,显示跨域调用成功
2> 现在我们在 jsonp.html页面定义一个函数,然后在远程 server.js 中传入数据进行调用
jsonp.html页面代码如下:
<!-- jsonp.html -->
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript">
var localHandler = function(data) {
alert(
"我是本地函数,可以被跨域的 server.js 文件调用,远程js带来的数据是:" +
data.result
);
};
</script>
<script type="text/javascript" src="http://server.com/server.js"></script>
</head>
<body></body>
</html>
server.js 文件代码如下:
// server.js
localHandler({
result: "我是远程js带来的数据"
});
运行之后查看结果,页面成功弹出提示窗口,显示本地函数被跨域的远程 js 调用成功,并且还接受到了远程 js 带来的数据。但是又一个问题出现了,**怎么让远程 js 知道他应该调用的本地函数叫什么名字呢?**毕竟是 JSONP 的服务者都要面对很多服务对象,而这些服务对象各自的本地函数都不相同啊
3> 我们可以这样想,只要服务端提供的 js 脚本是动态生成的就行了呗,这样调用者可以传一个参数过去告诉服务端"我想要一段调用 XXX 函数的代码,请你返回给我",于是服务器就可以按照客户端的需求来生成 js 脚本并响应了。
jsonp.html页面的代码
<!-- jsonp.html -->
<!DOCTYPE html>
<html>
<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>
这次的代码变化比较大,不再直接把远程 js 文件写死,而是编码实现动态查询,而这也正是 JSONP 客户端实现的核心部分
flightHandler({
code: "CA1998",
price: 1780,
tickets: 5
});
我们看到,传递给 flightHandler 函数的是一个 json ,它描述了航班的基本信息。运行一下页面,成功的弹出提示窗口,JSONP 的执行全过程顺利完成。
原生 JS 实现 JSONP 的步骤
客户端
- 定义获取数据后调用的回调函数
- 动态生成对服务端 JS 进行引用的代码
- 设置
url为提供jsonp服务的url地址,并在该url中设置相关callback参数 - 创建
script标签,并设置其src属性 - 把
script标签加入head中,此时调用开始
- 设置
服务端
将客户端发送的callback参数作为函数名来包裹住 JSON 数据,返回数据至客户端
JSONP 与 GET/POST 请求
我们知道script,link,img等标签引入外部资源,都是GET请求,那么就决定了JSONP 一定是 GET 请求,即便在$.ajax()中使用POST请求也能成功。一旦我们指定了dataType: 'jsonp',不管 type的值是什么(GET/POST/甚至不写),都会进行GET请求。
这是 jquery 在封装 JSONP 跨域时就已经写死了的
// 对应的源码
jQuery.ajaxPrefilter("script", function(s) {
if (s.cache === undefined) {
s.cache = false;
}
if (s.crossDomain) {
s.type = "GET";
s.global = false;
}
});
AJAX 与 JSONP 的异同
- AJAX 和 JSONP 这两种技术在调用方式上"看起来"很像,目的也一样,都是请求一个
url,然后把服务器返回的数据进行处理,因此有的框架都把 JSONP 作为 AJAX 的一种形式进行了封装 - AJAX 和 JSONP 其本质上是不同的东西
- AJAX 的核心是通过
XmlHttpRequest获取非本页内容 - JSONP 的核心则是动态添加
<script>标签来调用服务器提供的 js 脚本
- AJAX 的核心是通过
- 两者区别联系
- 区别不在于是否跨域
- AJAX 通过服务端代理一样可以实现跨域
- JSONP 本身也不排斥同域的数据的获取
- JSONP 是一种方式或者说是非强制性的协议
- JSONP 只支持 GET 请求,AJAX 支持 GET 和 POST 请求
希望对读完本文的你有帮助、有启发,如果有不足之处,欢迎批评指正交流!
欢迎关注我的个人博客分享一些前端技术、面试题、面试技巧等
辛苦整理良久,还望手动点赞鼓励~
'摘抄'不是单纯的“粘贴->复制”,而是眼到,手到,心到的一字一句敲打下来。
博客声明:所有转载的文章、图片仅用于作者本人收藏学习目的,被要求或认为适当时,将标注署名与来源。若不愿某一作品被转用,请及时通知本站,本站将予以及时删除。