如何实现在纯 Web 端完成各类 API 调试?

在软件开发过程中,对于各类 API 的调试工作至关重要。API调试是验证和测试应用程序接口的有效性和正确性的关键步骤。传统的API调试方法通常依赖于独立的工具或桌面应用程序,限制了调试过程的灵活性和效率。

为推动API调试向更便捷、高效的方向发展,越来越多的开发人员开始寻求在纯Web端完成各类API调试的解决方案。纯Web端的API调试具有许多优势,包括无需安装额外软件、跨平台支持、便于团队协作等。本文将以开源项目 AREX 为例为大家介绍如何在 Web 端实现对各类 API 的调试功能。

关于 AREX

AREX (http://arextest.com/)是一款开源的基于真实请求与数据的自动化回归测试平台,利用 Java Agent 技术与比对技术,通过流量录制回放能力实现快速有效的回归测试。同时提供了接口测试、接口比对测试等丰富的自动化测试功能。

难点一:跨域限制

要想在纯 Web 端实现各类 API 的调试工作,首先要解决的难题是处理浏览器的跨域限制。

什么是跨域

浏览器跨域问题是指在 Web 开发中,当使用 JavaScript 代码从一个域名的网页访问另一个域名的资源时会遇到的限制。浏览器实施了一种安全策略,称为同源策略(Same-Origin Policy), 用于保护用户信息的安全。同源策略要求网页中的 JavaScript 只能访问与其来源(协议、域名和端口号)相同的资源,而对于不同域名的资源访问会受到限制。

由于浏览器存在跨域限制,我们不能在浏览器端随心所欲地发送 HTTP 请求,这是浏览器的安全策略决定的。

解决方案

经调研,突破此限制的方法有两种:分别是 **Chrome** 插件代理服务端代理,以下是两种方法的比较。

Chrome 插件代理服务端代理
访问本地可以不可以
速度无请求时间损耗整个流程速度受代理接口影响
实际请求已知 Origin 源会被修改为 Chrome 插件的源完全一样

权衡下来 AREX 选择了 Chrome 插件代理的方法,其原理是利用了 Chrome 插件中 background 可以发送跨域请求的能力,我们将浏览器端拦截到的请求通过 window.postmassage 与 Chrome 插件的 background 进行通信(其中通信还需要 Chrome 插件的 content-script作为数据桥梁)。

具体实现如下:

  • 在页面脚本中
  1. 生成一个随机的字符串,并将其转换为字符串形式,存储在 `tid` 变量中。

  2. 使用 window.postMessage() 方法发送一条消息到其他扩展程序,消息包括一个类型为 AREX_EXTENSION_REQUEST 的标识、tid、以及 params 参数。

  3. 添加一个 message 事件监听器 receiveMessage,用于接收其他扩展程序发送的消息。

4. 在 receiveMessage 函数中,检查接收到的消息是否为类型为 AREX\_EXTENSION_RES,并且 tid 与之前发送的消息的 tid 相匹配。如果匹配成功,则移除事件监听器。

  • 在内容脚本中
  1. 添加一个 message 事件监听器,用于接收来自页面脚本或其他扩展程序发送的消息。

  2. 在事件监听器中,检查接收到的消息是否为类型为 AREX\_EXTENSION\_REQUEST,如果是,则使用 chrome.runtime.sendMessage() 方法将消息发送给后台脚本。

  3. 在接收到来自后台脚本的响应后,使用 window.postMessage() 方法将响应消息发送回页面脚本或其他扩展程序。

  • 在后台脚本中
  1. 使用 chrome.runtime.onMessage.addListener() 方法添加一个监听器,用于接收来自内容脚本或其他扩展程序发送的消息。

  2. 在监听器中可以处理接收到的消息,并根据需要作出响应。

// arex
const tid = String(Math.random());
window.postMessage(
  {
    type: '__AREX_EXTENSION_REQUEST__',
    tid: tid,
    payload: params,
  },
  '*',
);
window.addEventListener('message', receiveMessage);
function receiveMessage(ev: any) {
  if (ev.data.type === '__AREX_EXTENSION_RES__' && ev.data.tid == tid) {
    window.removeEventListener('message', receiveMessage, false);
  }
}
// content-script.js
window.addEventListener("message", (ev) => {
  if (ev.data.type === "__AREX_EXTENSION_REQUEST__"){
    chrome.runtime.sendMessage(ev.data, res => {
      //   与background通信
      window.postMessage(
        {
          type: "__AREX_EXTENSION_RES__",
          res,
          tid:ev.data.tid
        },
        "*"
      )
    })
  }
})
// background.js
chrome.runtime.onMessage.addListener((req, sender, sendResponse) => {

})

难点二:API 调试

上述已经解决了跨域问题,接下来就是如何实现 API 调试的功能。

解决方案

Postman 是业内成熟的 API 调试工具,我们站在了 Postman 这位巨人的肩膀上,在 AREX 中引入了 Postman 的 JavaScript 沙盒,使用它的沙盒运行前置脚本、后置脚本以及断言来调试 API。

以下是 AREX 请求的流程图:

当点击发送请求的时候,会将表单中的数据汇聚到一起,数据结构为:

export interface Request {
  id: string;
  name: string;
  method: string;
  endpoint: string;
  params: {key:string,value:string}[];
  headers: {key:string,value:string}[];
  preRequestScript: string;
  testScript: string;
  body: {contentType:string,body:string};
}

这是 AREX 的数据结构,我们会将其转换成 Postman 的数据结构。之后调用 `PostmanRuntime.Runner() `方法,将转换好了的 Postman 数据结构和当前所选的环境变量传入,Runner 会执行 `preRequestScript` 和 `testScript` 脚本。`preRequestScript` 发生在请求之前,可以在其中穿插请求以及对请求参数、环境变量进行操作,`testScript` 发生在请求之后,可以对 response 返回数据进行断言操作,并且脚本中也可以通过 ``console.log`` 输出数据,在控制台进行调试。

var runner = new runtime.Runner(); // runtime = require('postman-runtime');

// 一个标准的postman集合对象
var collection = new sdk.Collection();

runner.run(collection, {}, function (err, run) {
    run.start({
      assertion:function (){}, //断言
      prerequest:function (){}, // 预请求勾子
      test:function (){}, //测试勾子
      response:function (){} //返回勾子
    });
});

在 Postman 沙盒中也存在跨域问题,由于 Postman 沙盒的集成度非常高,为了确保与 PostmanRuntime 的同步以及方便性,我们采用了 Ajax 拦截技术。通过在浏览器端拦截 Ajax 请求,我们可以对请求进行修改、添加自定义逻辑或者进行其他处理操作。这样可以实现对请求和响应的全局控制和定制化。

当 Postman 沙盒发送请求时,会携带一个名为 “postman-token” 的请求头。我们拦截到这个 Ajax 请求后,会将请求参数进行拼装,并通过 window.postMessage 发送给浏览器插件。浏览器插件再次构建 fetch 请求,将数据返回给 Postman 沙盒,使其输出最终结果,包括响应(response)、测试结果(testResult)和控制台日志(console.log)。需要注意的是,responseType 必须指定为 arraybuffer。

具体流程如下:

  1. 使用 xspy.onRequest() 方法注册一个请求处理程序。这个处理程序接受两个参数:request 和 sendResponse。request 参数包含请求的相关信息,例如方法、URL、头部、请求体等。sendResponse 是一个回调函数,用于发送响应给请求方。

2. 在处理程序中,通过检查请求的头部中是否存在 postman-token 来判断请求是否来自 Postman。

  • 如果存在该头部,表示请求是通过 Postman 发送的。则使用 AgentAxios 发起一个新的请求,使用原始请求的方法、URL、头部和请求体。AgentAxios 返回一个 agentData 对象,其中包含了响应的状态码、头部和数据等信息。创建一个名为 dummyResponse 的响应对象,包含了与原始请求相关的信息。dummyResponse 的 status 字段为 agentData 的状态码,headers 字段为将 agentData 的头部数组转换为对象格式的结果,ajaxType 字段为字符串 xhr,responseType 字段为字符串 arraybuffer,response 字段为将 agentData 的数据转换为 JSON 字符串并用 Buffer 包装的结果。最后,使用 sendResponse(dummyResponse) 将响应发送给请求方。

  • 如果请求不是来自 Postman,则直接调用 sendResponse(),表示不返回任何响应。

xspy.onRequest(async (request: any, sendResponse: any) => {
  // 判断是否是pm发的
  if (request.headers['postman-token']) {
    const agentData: any = await AgentAxios({
      method: request.method,
      url: request.url,
      headers: request.headers,
      data: request.body,
    });
    const dummyResponse = {
      status: agentData.status,
      headers: agentData.headers.reduce((p: any, c: { key: any; value: any }) => {
        return {
          ...p,
          [c.key]: c.value,
        };
      }, {}),
      ajaxType: 'xhr',
      responseType: 'arraybuffer',
      response: new Buffer(JSON.stringify(agentData.data)),
    };
    sendResponse(dummyResponse);
  } else {
    sendResponse();
  }
});

难点三:二进制对象序列化传递

还有一点值得一提,对于 x-www-form-urlencodedRaw 类型的请求,由于它们都是普通的 JSON 对象,处理起来比较容易。但是对于 form-databinary 类型的请求,需要支持传输二进制文件负载。然而,Chrome 插件的 postMessage 通信方式不支持直接传递二进制对象,导致无法直接处理这两种类型的请求。

解决方案

为了解决这个问题,AREX 采用了 base64 编码技术。在用户选择文件时,AREX 会将二进制文件转换为 base64 字符串,然后进行传输。在 Chrome 插件端,AREX 会将 base64 数据进行解码,并用于构建实际的 fetch 请求。这样可以绕过直接传递二进制对象的限制。

这个流程图描述了将 FormData 中的二进制文件转换为 Base64 字符串,并通过 Chrome 插件代理将其转换回文件并进行进一步处理的过程。

  1. form-data binary(A):表示一个包含二进制文件的 FormData 表单数据。

  2. FileReader(B):使用 FileReader 对象来读取二进制文件。

  3. readAsDataURL base64 string:FileReader 使用 readAsDataURL 方法将二进制文件读取为 Base64 字符串。

  4. Chrome 插件代理(C):Base64 字符串经过读取操作后,传递给 Chrome 插件代理进行进一步处理。

  5. base64 string:表示经过 FileReader 读取二进制文件后得到的 Base64 字符串。

  6. Uint8Array(D):在 Chrome 插件代理中,将 Base64 字符串转换为 Uint8Array。

  7. File(E):使用 Uint8Array 的数据创建一个新的 File 对象。

  8. fetch(F):将新创建的 File 对象通过 fetch 方法或其他方式进行进一步处理,例如上传到服务器或进行其他操作。

代码分析

以下是代码层面的分析:

toBase64 函数接受一个 File 对象作为参数,并返回一个 Promise 对象,该 Promise 对象将解析为表示文件的 Base64 字符串。

在函数内部,创建了一个 FileReader 对象。 通过调用 reader.readAsDataURL(file) 将文件读取为 Data URL。 当读取操作完成时,通过 reader.onload 事件处理程序将读取结果解析为字符串,并使用 resolve 将其传递给 Promise。 如果发生错误,将使用 reject 将错误传递给 Promise。 base64ToFile 函数接受两个参数:dataurl(Base64 字符串)和 filename(文件名),并返回一个 File 对象。

首先,将 dataurl 使用逗号分割成数组 arr,如果分割结果为空,则将其设为包含一个空字符串的数组。 通过正则表达式匹配 arr[0] 中的内容,提取出 MIME 类型,即数据的类型。 使用 atob 将 Base64 字符串解码为二进制字符串 bstr。 创建一个长度为 n 的 Uint8Array 数组 u8arr。 使用循环遍历 bstr,将每个字符的 Unicode 编码放入 u8arr 中。 最后,使用 File 构造函数创建并返回一个新的 File 对象,其中包含了从 u8arr 中读取的文件数据、文件名和 MIME 类型。 导出 base64ToFile 函数,以便在其他地方使用。

// 文件转Base64
const toBase64 = (file: File): Promise<string> =>
  new Promise((resolve, reject) => {
    const reader = new FileReader();
    reader.readAsDataURL(file);
    reader.onload = () => resolve(reader.result as string);
    reader.onerror = reject;
  });
// base64转文件
function base64ToFile(dataurl: string, filename: string) {
  const arr = dataurl.split(',') || [''],
    mime = arr[0].match(/:(.*?);/)?.[1],
    bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
}

export default base64ToFile;

  • AREX 文档:arextest.com/zh-Hans/doc…

  • AREX 官网:arextest.com/

  • AREX GitHub:github.com/arextest

  • AREX 官方 QQ 交流群:656108079

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
【资源说明】 该项目是个人毕设项目源码,评审分达到95分,都经过严格调试,确保可以运行!放心下载使用。 该项目资源主要针对计算机、自动化等相关专业的学生或从业者下载使用,也可作为期末课程设计、课程大作业、毕业设计等。 具有较高的学习借鉴价值!基础能力强的可以在此基础上修改调整,以实现类似其他功能。 开发软件: Eclipse或者Idea + HbuilderX + Mysql + Redis 开发技术: uni-app 是一个使用vue的语法 + 微信小程序的标签和API的跨平台前端框架,开发者编写一套代码,可编译到iOS、Android、H5、小程序等多个平台,几乎覆盖所有流量;后接口才有java语言的Springboot技术开发 后台登录地址:http://localhost:8888/gp/login 管理员账号密码: admin/123456 用户账号密码:ys4/123456 骑手账号密码:pt4/123456 功能介绍: 系统一共3个身份:用户、跑腿员和管理员,其中用户和跑腿员在移动实现,管理员在web登录管理,在移动可以注册成为用户或者跑腿人员。 用户登录后可以发布跑腿的订单,订单分类很多有外卖订单,购物订单,快递订单,打印订单和其他订单等。用户发布外卖订单和购物订单的时候可以选择要买的物品,相当于购物车的功能,选好物品后用户选择要配送的目的地址,填写好距离程序会自动计算跑腿费,个人中心用户可以修改自己的个人信息包括头像等,可以按照分类查询自己的订单,对于已经完成的订单用户和快递员可以双方互评,用户可以查看自己的账户流水记录,如果余额不足了用户还可以充值,用户和跑腿员都可以发布朋友圈动态和查看朋友圈,可以修改管理自己的收货地址,可以修改密码等。 跑腿人员注册后需要管理员认证后才可以接单,否则是不能接单的,跑腿人员可以查询所有用派发的各类订单,查看订单详情包括跑腿费,跑腿人员确认接单后开始配送物品,配送完毕后点击完成更新订单状态然后就进入了双方互评阶段了,跑腿人员在个人中心可以查看到自己已经挣到的金额,也可以查看自己的流水记录,发布朋友圈查看朋友圈,修改密码等。 管理员登录web后台后可以管理所有的交易订单,可以添加管理外卖饭菜,添加管理商品货物,管理文章分类,添加管理文章信息,认证骑手,管理所有用户信息,管理角色信息,管理网站菜单信息,项目参数配置等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值