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

article/2024/12/22 2:21:29

01c83946fc6359a1a4c2ca7c15d6c4d4.gif

作者 | 张涛,携程机票研发部高级软件工程师

责编 | 夏萌

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

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

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

398cc420cb9ff017b8b3e6e81c353903.png

难点一:跨域限制

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

什么是跨域

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

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

解决方案

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

c2b5e6529764b6776aae65a1c134f1a5.jpeg

权衡下来 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. 在监听器中可以处理接收到的消息,并根据需要作出响应。

```
// arexconst 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.jschrome.runtime.onMessage.addListener((req, sender,sendResponse) => {})```

1a1ebc4a3dda84bc70f4e894d1d32e27.png

难点二:API 调试

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

解决方案

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

以下是 AREX 请求的流程图:

022ca0d9f4e55f4bdd6dcd3b26dd0095.png

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

```
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(); }});```

5baaf8f80e90a2f25edcc52b2b078a74.png

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

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

解决方案

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

就这个问题我们采用了 base64 编码技术,在选择文件时我们会将二进制文件转换成 base64 字符串,再进行传输,Chrome 插件端会将 base64 数据解码并用于构建实际的 `fetch` 请求。

40d3b85490cfe218e154a35268c601ca.png

这个流程图描述了将 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 =>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;

推荐阅读:

▶快播公司已破产注销;ChatGPT 之父警告:AI 可能灭绝人类;苹果官方:618 将开启全球首次直播|极客头条

▶FBI 花 3 年暴力破解 iPhone X 密码,竟成一场空?法院:搜查令已过期,证据无效

▶Rust 社区管理再起“内讧”,外部专家遭排挤,核心成员主动请辞,立即生效!

c7ceb2d15357c3ad92e59fd4f553cc4b.jpeg


http://chatgpt.dhexx.cn/article/wnF3STGa.shtml

相关文章

BASIC 之父出生 | 历史上的今天

整理 | 王启隆 透过「历史上的今天」,从过去看未来,从现在亦可以改变未来。 今天是 2023 年 5 月 31 日,在 1962 年的今天,伦纳德克兰罗克(Leonard Kleinrock)发表了他的第一篇论文,题为“大型通…

22字声明、近400名专家签署、AI教父Hinton与OpenAI CEO领头预警:AI可能灭绝人类!...

整理 | 屠敏 出品 | CSDN(ID:CSDNnews) 经过不到一年的时间,AI 的发展超乎所有人的想象,也大有失控的风险。 就在今天,全球部分顶尖的 AI 研究员、工程师和 CEO 就他们认为 AI 对人类构成的生存威胁发出了新…

时至 2023 年,2000 万行仍然是 MySQL 表的软限制吗?

一直有传言说,MySQL 表的数据只要超过 2000 万行,其性能就会下降。而本文作者用实验分析证明:至少在 2023 年,这已不再是 MySQL 表的有效软限制。 原文链接:https://yishenggong.com/2023/05/22/is-20m-of-rows-still-…

GPT-4 Copilot X震撼来袭!AI写代码效率10倍提升,码农遭降维打击

新智元报道 【新智元导读】GPT-4加强版Copilot来了!刚刚,GitHub发布了新一代代码生成工具GitHub Copilot X,动嘴写代码不再是梦。 微软真的杀疯了! 上周,微软刚用GPT-4升级了Office办公全家桶,还没等人们反…

FBI 花 3 年暴力破解 iPhone X 密码,竟成一场空?法院:搜查令已过期,证据无效...

整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 很难预料到,几年前 FBI 和苹果之间那场备受关注的隐私大战,时至今日仍有余波: ▶ 2016 年,正值苹果与 FBI “剑拔弩张”时,其安全指南曾声称…

发布 21 年后,Windows XP 被破解,仅 18KB 即可离线激活

整理 | 郑丽媛 出品 | CSDN(ID:CSDNnews) 都 2023 年了,如今再提起 Windows XP,可能颇有些“时代的眼泪”的味道。 (Windows XP 经典的默认桌面壁纸) 2001 年 10 月 25 日正式登陆零售商店&…

​iPhone 14 Pro 全系降价 700 元;Gmail 之父:有了 ChatGPT,搜索引擎活不过两年了|极客头条...

「极客头条」—— 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧。 整理 | 梦依丹 出品 | CSDN(ID:CSDNnews) 一分钟速览新闻点&#…

ChatGPT陷伦理风波 “纯净版”机器人在赶来的路上

近期,AI安全问题闹得沸沸扬扬,多国“禁令”剑指ChatGPT。自然语言大模型采用人类反馈的增强学习机制,也被担心会因人类的偏见“教坏”AI。 4月6日,OpenAI 官方发声称,从现实世界的使用中学习是创建越来越安全的人工智…

快播公司已破产注销;ChatGPT 之父警告:AI 可能灭绝人类;苹果官方:618 将开启全球首次直播|极客头条...

「极客头条」—— 技术人员的新闻圈! CSDN 的读者朋友们早上好哇,「极客头条」来啦,快来看今天都有哪些值得我们技术人关注的重要新闻吧。 整理 | 梦依丹 出品 | CSDN(ID:CSDNnews) 一分钟速览新闻点&#…

AI聊天机器人ChatGPT遭破解,引发数据泄露风险

近日,一款基于人工智能技术的聊天机器人——ChatGPT遭受黑客攻击,导致用户数据泄露风险加大。这一事件引起了广泛的关注,也引发了人们对于人工智能安全性的担忧。 ChatGPT是一种被广泛应用于企业客户服务和市场营销等领域的AI聊天机器人&…

行走的代码生成器:chatGPT要让谷歌和程序员“下岗”了

就在本周,OpenAI 又发布了一个全新的聊天机器人模型 ChatGPT,作为 GPT-3.5 系列的主力模型之一。 图片来源:OpenAI 更重要的是它是完全免费公开的!所以一经发布大家立刻就玩开了——很快,网友们就被 ChatGPT 的能力所…

【ChatGPT】ChatGPT 能否取代程序员?

Yan-英杰的主页 悟已往之不谏 知来者之可追 C程序员,2024届电子信息研究生 目录 前言: ChatGPT 的优势 自然语言的生成 文本自动生成 建立了更人性化的人机交互 ChatGPT 的局限性 算法的解释能力较差 程序的可实现性较差 缺乏优化和质量控制 程序员相较于 …

ChatGPT或许很强大,但还抢不走你的饭碗

ChatGPT变得家喻户晓是在2022年的11月,当时OpenAI正式对外推出了GPT3.5。 但实际上,这场AI革命的战争早已开始打响。过去十年间,谷歌、 脸书、亚马逊、苹果和微软这些硅谷有名有姓的科技巨头纷纷开启AI“军备竞赛”,先后成立专门…

昨天,我被ChatGPT抢饭碗了!

分享人:Mr.K 作者:ChatGPT 昨天,K哥发了一条朋友圈:我用ChatGPT写的演讲稿,跟企业家同学们分享《AIGC如何赋能企业》。 不要再说AI离你还很远,AI代替人类工作还早。抛弃你的从来不是时代,而是…

危!ChatGPT一出,这10大职业可能先丢饭碗

👇👇关注后回复 “进群” ,拉你进程序员交流群👇👇 来源丨新智元 https://mp.weixin.qq.com/s/AY8qtV9c14sXiZ8juGZ9Pw 新智元报道 编辑:David 【新智元导读】ChatGPT一出,很多人害怕自己的工…

【ChatGPT】你会是被AI抢饭碗的那类人吗?

文章目录 前言一、AI替代“基础性工作”,二、AI没有魔法:人类做不到,它也做不到三 人类的恐惧:被替代、被超越四 AI让语言返祖,小语种与文化“濒危灭绝”五 人类的未来,教育何去何从?总结 前言 …

“拿下”谷歌124万年薪offer,ChatGPT将取代程序员?

#ChatGPT会抢谁饭碗# #ChatGPT会不会使基层程序员失业# .... ChatGPT横空出世直接霸屏各大平台热搜榜单,刷爆朋友圈,引发全球ChatGPT概念股集体疯涨。ChatGPT推出仅2个月,它的活跃用户已破1个亿,在1月份的访问量约为5.9亿。成为史…

ChatGPT面世具有何意义?ChatGPT会不会取代程序员?

本篇文章给大家谈谈ChatGPT面世具有何意义一个有趣的事情,以及ChatGPT会不会取代程序员一个有趣的事情,希望对各位有所帮助,不要忘了收藏本站喔。 1、chatgpt是什么? chatgpt介绍如下: ChatGPT是由人工智能研究实验室OpenAI在202…

最近大热的 chatGPT 会取代你的工作吗?

ChatGPT 由于其高效的自然语言处理能力,它最容易取代的领域可能是: 文本分类:ChatGPT 可以用作文本分类系统,对文本进行分类 聊天机器人:ChatGPT 可以制作聊天机器人,提供人性化的交互体验 文本生成&…

ChatGPT这是要抢走我的饭碗?我10年硬件设计都有点慌了

前 言 呃……问个事儿,听说ChatGPT能写电路设计方案了,能取代初级工程师了?那我这工程师的岗位还保得住么?心慌的不行,于是赶紧打开ChatGPT问问它。 嘿,还整的挺客气,快来看看我的职业生涯是否…