转载

(Ajax) 浅谈 JSONP 的原理与实现

一、什么是 JSONP

1.1 同源策略

如果两个页面拥有相同的 协议端口 (如果指定),和 主机 ,那么这两个页面就属于同一个

同源策略分为:

  • DOM 同源策略:禁止对不同源页面 DOM 进行操作

  • XMLHttpRequest 同源策略:禁止向不同源的地址发起 HTTP 请求

    由此可见, Ajax 禁止跨域。

1.2 JSONP 的原理

JSONPJSON with Padding 的简称,一般用来解决 Ajax 跨域的问题。它是这样产生的:

  1. 页面上调用 js 文件时不受跨域的影响,而且,凡是拥有 src 属性的标签都拥有跨域的能力,比如 <script><img><iframe>

  2. 可以在远程服务器上设法把数据装进 js 格式的文件里,供客户端调用处理,实现跨域。

  3. 目前最常用的数据交换方式是 JSON ,客户端通过调用远程服务器上动态生成的 js 格式文件(一般以 JSON 后缀)。

  4. 客户端成功调用 JSON 文件后,对其进行处理。

  5. 为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作 JSONP ,该协议的一个要点就是允许用户传递一个 callback 参数给服务端,然后服务端返回数据时会将这个 callback 参数作为函数名来包裹住 JSON 数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

二、 JSONP 的客户端具体实现

2.1 上文已指出,页面可执行跨域的 js 代码(符合安全策略的),那么:

<script type="text/javascript">
  var localHandler = function (data) {
    alert('跨域的remote.js文件可以调用本函数,带来的数据是:' + data.result);
  };
</script>
<script type="text/javascript" src = "http://remoteserver.com/remote.js"></script>

remote.js 的代码:

localHandler({
  "result": "我是远程js带来的数据"
});

运行后,成功弹出提示窗口,跨域成功。但问题是,如何让远程 js 知道它应该调用的本地函数叫什么名字?

2.2 只要服务端提供的 js 脚本是动态生成的就行了,调用者可以传一个参数过去告诉服务端本地函数的名字,于是服务端就可以按照客户的需求来生成 js 脚本并相应了。

var flightHandler = function (data) {
    alert('你查询的航班结果是:票价 ' + data.price + '元,余票' + data.tickets + '张。');
  };
  var url = 'http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998&callback=flightHandler';
  var script = document.createElement('script');
  script.setAttribute('src', url);
  document.getElementsByTagName('head')[0].appendChild(script);

并没有直接把远程 js 写死,而是编码事项动态查询。这是 JSONP 的核心部分。在调用的 url 中传递了一个 code 参数,告诉服务器要查的是 CA1998 次航班的信息,而 callback 参数告诉服务器,本地调用的函数叫做 flightHandler

服务器的 flightResult.aspx 生成了以下代码提供给页面:

flightHandler({
  "code": "CA1998",
  "price": 1780,
  "tickets": 5
});

运行一下页面,成功提示窗口, JSONP 的执行全过程顺利完成。

2.3 jQuery 代码

$(function() {
  $('button').on('click', function(event) {
    event.preventDefault();
    $.ajax({
      type: 'GET',
      async: false,
      url: 'http://flightQuery.com/jsonp/flightResult.aspx?code=CA1998',
      dataType: 'jsonp',
      jsonp: 'callback',
      jsonpCallback: 'flightHandler',  // 默认为jQuery自动生成的随机函数名
      success: function (json) {
        alert('你查询的航班结果是:票价 ' + json.price + '元,余票' + json.tickets + '张。');
      },
      error: function () {
        alert('fail');
      }
    });
  });
});

jQuery 自动生成回调函数并把数据取出来供 success 属性方法来调用。

三、 JSONPAjax 的关系

  • AjaxJSONP 这两种技术看起来很像,目的也一样,都是请求一个 url ,然后把服务器返回的数据进行处理,因此 jQuery 等框架都把 JSONP 作为 Ajax 的一种形式。

  • 实际上 AjaxJSONP 有着本质上的不同。 Ajax 的核心是通过 XMLHttpRequest 获取数据,而 JSONP 的核心则是动态添加 <script> 标签来调用服务器提供的 js 文件。

  • AjaxJSONP 的区别也不在于是否跨域, Ajax 通过服务端代理也可以跨域, JSONP 也可获取同源数据。

四、参考

  1. 【原创】说说JSON和JSONP,也许你会豁然开朗,含jQuery用例

  2. 深入浅出JSONP--解决ajax跨域问题

  3. 浏览器的同源策略 - MDN

原文  https://segmentfault.com/a/1190000007232373
正文到此结束
Loading...