前端更优雅的使用 jsonp

前端更优雅的使用 jsonp

背景:最近项目中又使用到了 jsonp 这一项跨域的技术,(主要还是受同源策略影响),下面有为大家提供封装好的函数及对应使用示例,欢迎大家阅读理解

同源策略的介绍

同源策略是由 Netscape 公司提出的安全策略,现在所有支持 JavaScript 的浏览器都会使用这个策略。

所谓同源是指域名、协议、端口都相同。以 http://www.xxxxx.com:80/ 为例,http:// 为协议,域名是 www.xxxxx.com,端口是80。

为了安全,浏览器不允许进行跨域请求。当我们通过 Ajax 在网页和服务器之间发送或接收数据时,需要保证网页与所请求的地址是同源的,否则无法请求成功。同源策略可以防止 JavaScript 脚本从您的网站中读取数据,并将数据发送到其它的网站。如果没有同源策略,很有可能会有恶意的程序泄露您网站中的内容。

虽然同源策略在一定程度上提高了网站的安全,但也会给开发带来一些麻烦,例如在访问一些开发接口时,由于同源策略的存在,会调用失败。要解决这种问题就需要用到跨域,跨域的方法有许多种,其中最经典的就是 JSONP。

JSONP 介绍

JSONP 全称“JSON with Padding”,译为“带回调的 JSON”,它是 JSON 的一种使用模式。通过 JSONP 可以绕过浏览器的同源策略,进行跨域请求。

  • 在进行 Ajax 请求时,由于同源策略的影响,不能进行跨域请求,而 script 标签的 src 属性却可以加载跨域的 JavaScript 脚本,JSONP 就是利用这一特性实现的。

  • 与 Ajax 的区别:在使用 JSONP 进行跨域请求时,服务器不再返回 JSON 格式的数据,而是返回一段调用某个函数的 JavaScript 代码,在 src 属性中调用,来实现跨域。

  • 优点:JSONP 兼容性好,在一些老旧的浏览器种也可以运行。

  • 缺点:只能进行 GET 请求。

JSONP 的使用

前端的 jsonp 异步函数封装

思路:

  1. 每调用一次 jsonp,生成唯一的 callback 回调函数 key,注册在 window 对象。
  2. 后端收到请求后,返回一个以 callback 参数作为函数名的函数的调用和一系列参数。
  3. 响应完成,处理完数据后,自动的移除掉 script 标签,window 注册的回调函数。
// 序列化参数
function serializeParams(params: { [x: string]: string | number | boolean }) {
  return Object.keys(params)
    .map(
      (key) => encodeURIComponent(key) + "=" + encodeURIComponent(params[key])
    )
    .join("&");
}

function jsonp(url: string, params = {}) {
  // 生成唯一的回调函数名
  const callbackName: string = `jsonp_${Date.now()}`;

  const script = document.createElement("script");
  script.src = `${url}?${serializeParams(params)}&callback=${callbackName}`;
  document.body.appendChild(script);

  return new Promise((resolve, reject) => {
    // 注册全局回调函数
    window[callbackName] = (data: unknown) => {
      resolve(data);
      // 删除 script 标签
      document.body.removeChild(script);
      // 删除全局回调函数
      delete window[callbackName];
    };

    // 错误处理
    script.onerror = () => {
      reject(new Error("JSONP request failed."));
      // 删除 script 标签
      document.body.removeChild(script);
      // 删除全局回调函数
      delete window[callbackName];
    };
  });
}

前端 jsonp 使用示例:

  • 服务端对应处理下面 ↓
const getUserInfo = async () => {
  let apiRoot = "http://localhost:3000";
  let userInfo = await jsonp(`${apiRoot}/userInfo`, { name: "小名" });
  console.log(userInfo);
  //拿到数据处理逻辑即可
};
getUserInfo();

前端执行收到响应结果如下:
响应结果
打印结果

服务端的逻辑示例

思路:

  • 收到前端的请求后,根据参数信息返回调用前端函数名和一系列参数的 json 字符串的响应格式。
  • 该示例使用了 node express 框架,同学自行了解
let express = require("express"); //node 框架
let url = require("url");
let app = express();

app.get("/userInfo", function (req, res) {
  //参数解析
  let urlParams = url.parse(req.url, true);
  console.log(urlParams, "url参数");
  if (urlParams.query.callback) {
    let userInfoRes = `${urlParams.query.callback} (${JSON.stringify({
      name: urlParams.query.name ?? "张三",
      age: 21,
    })})`;
    console.log(userInfoRes, "jsonp 响应结果");
    res.end(userInfoRes);
  } else {
    res.end("404");
  }
});

app.listen(3000);

后端收到请求结果如下:
请求结果

总结:上述代码中

  • jsonp 的使用一定是前后端的紧密配合,文档的模糊也会导致后期维护艰难。

有疑问的同学可以私信我、对帮助到同学欢迎大家点赞、收藏评论。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值