跨域问题之jsonp

前几天写了一篇关于ajax跨域的问题,总结了常见的几种容易混淆的问题,顺带讲了些原理。今天这篇主要是说明 ajax 跨域经常使用的一种办法 jsonp 的原理和具体实现,代码存放在 github 上 js-cross-origin, 使用了 hapi 这个 nodejs 框架。感兴趣的能够 star 和 watch,我这几天有空会持续更新代码。javascript

jsonp 详解

为了叙述方便,咱们把ajax的发出方,咱们浏览器上的加载好的网页的域称为源域,将ajax要访问的远端api所在的域称为目标域,这两个域不一样。因为浏览器的同源策略的,源域中的ajax访问目标域api,会触发跨域访问错误。前端

clipboard.png

No 'Access-Control-Allow-Origin' header is present on the requested resource.

幸运的是,script标签目标源的js文件并不会有问题。因此聪明的前端工程师想出了一个办法。java

  • 网页端插入一个script标签,src指向目标api 的 url(只能是 get api,由于 script 加载 js 文件是 http get 方法)。这里作一个小改动,url后面加上 query,?callback=handlenode

  • 后端 api 处理函数接收到请求,发现有 callback 参数,则将参数值拿下来,获得 handlegit

  • 后端用 handle 包装数据,返回给浏览器,注意,返回的 content-type 必须是 text/javascript; charset=utf-8github

  • 网页端 script 内容加载完成web

    handle(data)

    浏览器发现内容是 js(查看 content-type),则调用js解释器执行 handle(data)ajax

至此,jsonp 流程完成。json

常见的几种问题

为何 jsonp 只能访问后台 GET API?

jsonp 利用 script 标签加载 js 脚本不受同源策略的影响这个特性,绕过跨域限制。由于 script 加载 js 脚本使用的是 http get 方法,因此 jsonp 也只能访问 GET API。 所以,后台其余类型的 API 也要改形成 GET 类型。segmentfault

我使用 xx 语言/框架,怎么作才能支持 jsonp ?

通常成熟的 web 框架都会具有 jsonp 支持,经过简单的配置,能够完成 jsonp 对服务端的如下几个要求。

  • 读取 callback 名,好比 handle

  • 将数据封装在 handle 中

  • 将封装好的内容做为 js 脚本内容返回,注意 content-type 必须为 text/javascript; charset=utf-8 以便浏览器正常解析执行 js

好比个人代码中,服务器端的配置。

server.route({
  method: 'GET',
  path:'/users', 
  config: {
    jsonp: 'callback',
  },
  handler: function (request, reply) {
    const jsonp = request.query.jsonp;
    const users = [ { id: '1', name: 'Ada'}, { id: '2', name: 'Bob' } ];
    
    if (jsonp) {
      return reply(`${jsonp}(${users})`); //hapi会自动将结果的content-type设置为 text/javascript; charset=utf-8
    } else {
      return reply(users); // 默认 content-type 是 application/json
    }
    
  }
});

若是运气很差框架恰好不支持,那也没必要担忧,按照上面的要求,先后端约定好,实现 jsonp 并不难。

征集问题

若是有其余关于 jsonp 的问题,欢迎留言,我会将典型的问题和解答,追加到上面。

相关文章
相关标签/搜索