国产玉足榨精视频在线_亚洲日韩国产第一区_男人都懂的网站在线观看免费_久久91亞洲精品中文字幕奶水_按摩房技师激情国产精品_无人在线观看视频在线观看_年轻女教师2免费播放_欧洲熟妇色xxⅩx欧美老妇多毛_91爱视频成人在线第一页_欧美日韩中文字幕成人网

日志樣式

重慶企業(yè)網(wǎng)站建設(shè)500元全包(webapi有哪些)webapi使用方法,

原標(biāo)題:如何實(shí)現(xiàn)在純 Web 端完成各類 API 調(diào)試?作者 | 張濤,攜程機(jī)票研發(fā)部高級(jí)軟件工程師責(zé)編| 夏萌在軟件開發(fā)過(guò)程中,對(duì)于各類 API 的調(diào)試工作至關(guān)重要API 調(diào)試是驗(yàn)證和測(cè)試應(yīng)用程序接口的有效性和正確性的關(guān)鍵步驟。

傳統(tǒng)的 API 調(diào)試方法通常依賴于獨(dú)立的工具或桌面應(yīng)用程序,限制了調(diào)試過(guò)程的靈活性和效率為推動(dòng) API 調(diào)試向更便捷、高效的方向發(fā)展,越來(lái)越多的開發(fā)人員開始尋求在純 Web 端完成各類 API 調(diào)試的解決方案。

純 Web 端的 API 調(diào)試具有許多優(yōu)勢(shì),包括無(wú)需安裝額外軟件、跨平臺(tái)支持、便于團(tuán)隊(duì)協(xié)作等本文將以開源項(xiàng)目 AREX 為例為大家介紹如何在 Web 端實(shí)現(xiàn)對(duì)各類 API 的調(diào)試功能AREX (http://arextest.com/)是一款開源的基于真實(shí)請(qǐng)求與數(shù)據(jù)的自動(dòng)化回歸測(cè)試平臺(tái),利用 Java Agent 技術(shù)與比對(duì)技術(shù),通過(guò)流量錄制回放能力實(shí)現(xiàn)快速有效的回歸測(cè)試。

同時(shí)提供了接口測(cè)試、接口比對(duì)測(cè)試等豐富的自動(dòng)化測(cè)試功能難點(diǎn)一:跨域限制要想在純 Web 端實(shí)現(xiàn)各類 API 的調(diào)試工作,首先要解決的難題是處理瀏覽器的跨域限制什么是跨域?yàn)g覽器跨域問(wèn)題是指在 Web 開發(fā)中,當(dāng)使用 Java 代碼從一個(gè)域名的網(wǎng)頁(yè)訪問(wèn)另一個(gè)域名的資源時(shí)會(huì)遇到的限制。

瀏覽器實(shí)施了一種安全策略,稱為同源策略(Same-Origin Policy), 用于保護(hù)用戶信息的安全同源策略要求網(wǎng)頁(yè)中的 Java 只能訪問(wèn)與其來(lái)源(協(xié)議、域名和端口號(hào))相同的資源,而對(duì)于不同域名的資源訪問(wèn)會(huì)受到限制。

由于瀏覽器存在跨域限制,我們不能在瀏覽器端隨心所欲地發(fā)送 HTTP 請(qǐng)求,這是瀏覽器的安全策略決定的解決方案經(jīng)調(diào)研,突破此限制的方法有兩種:分別是 Chrome 插件代理和 服務(wù)端代理, 以下是兩種方法的比較。

權(quán)衡下來(lái) AREX 選擇了 Chrome 插件代理的方法,其原理是利用了 Chrome 插件中 background 可以發(fā)送跨域請(qǐng)求的能力,我們將瀏覽器端攔截到的請(qǐng)求通過(guò) window.postmassage 與 Chrome 插件的 background 進(jìn)行通信(其中通信還需要 Chrome 插件的 content- 作為數(shù)據(jù)橋梁)。

具體實(shí)現(xiàn)如下:在頁(yè)面腳本中生成一個(gè)隨機(jī)的字符串,并將其轉(zhuǎn)換為字符串形式,存儲(chǔ)在 tid 變量中使用 window.postMessage 方法發(fā)送一條消息到其他擴(kuò)展程序,消息包括一個(gè)類型為 ` AREX_EXTENSION_REQUEST。

` 的標(biāo)識(shí)、tid、以及 params 參數(shù) 添加一個(gè) message 事件監(jiān)聽器 receiveMessage,用于接收其他擴(kuò)展程序發(fā)送的消息在 receiveMessage 函數(shù)中,檢查接收到的消息是否為類型為 。

AREX_EXTENSION_RES,并且 tid 與之前發(fā)送的消息的tid 相匹配如果匹配成功,則移除事件監(jiān)聽器 在內(nèi)容腳本中添加一個(gè) message 事件監(jiān)聽器,用于接收來(lái)自頁(yè)面腳本或其他擴(kuò)展程序發(fā)送的消息。

在事件監(jiān)聽器中,檢查接收到的消息是否為類型為 AREX_EXTENSION_REQUEST,如果是,則使用 chrome.runtime.sendMessage 方法將消息發(fā)送給后臺(tái)腳本 在接收到來(lái)自后臺(tái)腳本的響應(yīng)后,使用 window.postMessage 方法將響應(yīng)消息發(fā)送回頁(yè)面腳本或其他擴(kuò)展程序。

在后臺(tái)腳本中使用 chrome.runtime.onMessage.addListener 方法添加一個(gè)監(jiān)聽器,用于接收來(lái)自內(nèi)容腳本或其他擴(kuò)展程序發(fā)送的消息在監(jiān)聽器中可以處理接收到的消息,并根據(jù)需要作出響應(yīng)。

```// arexconst tid = String(Math.random);window.postMessage({ type: __AREX_EXTENSION_REQUEST__, tid: tid,

payload: params, }, *,);window.addEventListener( message, receiveMessage); functionreceiveMessage(ev: any) {

if(ev.data.type === __AREX_EXTENSION_RES__&& ev.data.tid == tid) { window.removeEventListener( message

, receiveMessage, false); }}// content-.jswindow.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) => {})```難點(diǎn)二:API 調(diào)試上述已經(jīng)解決了跨域問(wèn)題,接下來(lái)就是如何實(shí)現(xiàn) API 調(diào)試的功能解決方案Postman 是業(yè)內(nèi)成熟的 API 調(diào)試工具,我們站在了 Postman 這位巨人的肩膀上,在 AREX 中引入了 Postman 的 Java 沙盒,使用它的沙盒運(yùn)行前置腳本、后置腳本以及斷言來(lái)調(diào)試 API。

以下是 AREX 請(qǐng)求的流程圖:

當(dāng)點(diǎn)擊發(fā)送請(qǐng)求的時(shí)候,會(huì)將表單中的數(shù)據(jù)匯聚到一起,數(shù)據(jù)結(jié)構(gòu)為:```exportinterfaceRequest{ id: string; name: string; method: string; endpoint

: string; params: {key:string,value:string} []; headers: { key:string,value:string} []; preRequest: string

; test: string; body: { contentType:string,body:string}; }```這是 AREX 的數(shù)據(jù)結(jié)構(gòu),我們會(huì)將其轉(zhuǎn)換成 Postman 的數(shù)據(jù)結(jié)構(gòu)之后調(diào)用 PostmanRuntime.Runner 方法,將轉(zhuǎn)換好了的 Postman 數(shù)據(jù)結(jié)構(gòu)和當(dāng)前所選的環(huán)境變量傳入,Runner 會(huì)執(zhí)行 preRequest 和 test 腳本。

`preRequest` 發(fā)生在請(qǐng)求之前,可以在其中穿插請(qǐng)求以及對(duì)請(qǐng)求參數(shù)、環(huán)境變量進(jìn)行操作,`test` 發(fā)生在請(qǐng)求之后,可以對(duì) response 返回?cái)?shù)據(jù)進(jìn)行斷言操作,并且腳本中也可以通過(guò) `console.log` 輸出數(shù)據(jù),在控制臺(tái)進(jìn)行調(diào)試。

```var runner = new runtime.Runner; // runtime = require( postman-runtime); // 一個(gè)標(biāo)準(zhǔn)的postman集合對(duì)象var collection = new sdk.Collection;

runner.run(collection, {}, function(err, run) { run.start({assertion: function{}, //斷言 prerequest: function

{}, // 預(yù)請(qǐng)求勾子 test: function{}, //測(cè)試勾子 response: function{} //返回勾子 });});```在 Postman 沙盒中也存在跨域問(wèn)題,由于 Postman 沙盒的集成度非常高,為了確保與 PostmanRuntime 的同步以及方便性,我們采用了 Ajax 攔截技術(shù)。

通過(guò)在瀏覽器端攔截 Ajax 請(qǐng)求,我們可以對(duì)請(qǐng)求進(jìn)行修改、添加自定義邏輯或者進(jìn)行其他處理操作這樣可以實(shí)現(xiàn)對(duì)請(qǐng)求和響應(yīng)的全局控制和定制化當(dāng) Postman 沙盒發(fā)送請(qǐng)求時(shí),會(huì)攜帶一個(gè)名為 "postman-token" 的請(qǐng)求頭。

我們攔截到這個(gè) Ajax 請(qǐng)求后,會(huì)將請(qǐng)求參數(shù)進(jìn)行拼裝,并通過(guò) window.postMessage 發(fā)送給瀏覽器插件瀏覽器插件再次構(gòu)建 fetch 請(qǐng)求,將數(shù)據(jù)返回給 Postman 沙盒,使其輸出最終結(jié)果,包括響應(yīng)(response)、測(cè)試結(jié)果(testResult)和控制臺(tái)日志(console.log)。

需要注意的是,responseType 必須指定為 arraybuffer具體流程如下:使用 xspy.onRequest 方法注冊(cè)一個(gè)請(qǐng)求處理程序這個(gè)處理程序接受兩個(gè)參數(shù):request 和 sendResponse。

request 參數(shù)包含請(qǐng)求的相關(guān)信息,例如方法、URL、頭部、請(qǐng)求體等sendResponse 是一個(gè)回調(diào)函數(shù),用于發(fā)送響應(yīng)給請(qǐng)求方在處理程序中,通過(guò)檢查請(qǐng)求的頭部中是否存在 postman-token 來(lái)判斷請(qǐng)求是否來(lái)自 Postman。

如果存在該頭部,表示請(qǐng)求是通過(guò) Postman 發(fā)送的則使用 AgentAxios 發(fā)起一個(gè)新的請(qǐng)求,使用原始請(qǐng)求的方法、URL、頭部和請(qǐng)求體AgentAxios 返回一個(gè) agentData 對(duì)象,其中包含了響應(yīng)的狀態(tài)碼、頭部和數(shù)據(jù)等信息。

創(chuàng)建一個(gè)名為 dummyResponse 的響應(yīng)對(duì)象,包含了與原始請(qǐng)求相關(guān)的信息dummyResponse 的 status 字段為 agentData 的狀態(tài)碼,headers 字段為將 agentData 的頭部數(shù)組轉(zhuǎn)換為對(duì)象格式的結(jié)果,ajaxType 字段為字符串 xhr,responseType 字段為字符串 arraybuffer,response 字段為將 agentData 的數(shù)據(jù)轉(zhuǎn)換為 JSON 字符串并用 Buffer 包裝的結(jié)果。

最后,使用 sendResponse(dummyResponse) 將響應(yīng)發(fā)送給請(qǐng)求方如果請(qǐng)求不是來(lái)自 Postman,則直接調(diào)用 sendResponse,表示不返回任何響應(yīng)```xspy.onRequest(async (request: any, sendResponse: any) => {。

// 判斷是否是pm發(fā)的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; }});```難點(diǎn)三:二進(jìn)制對(duì)象序列化傳遞還有一點(diǎn)值得一提,對(duì)于 `x-www-form-urlencoded` 和 `Raw` 類型的請(qǐng)求,由于它們都是普通的 JSON 對(duì)象,處理起來(lái)比較容易。

但是對(duì)于 `form-data` 和 `binary` 類型的請(qǐng)求,需要支持傳輸二進(jìn)制文件負(fù)載然而,Chrome 插件的 `postMessage` 通信方式不支持直接傳遞二進(jìn)制對(duì)象,導(dǎo)致無(wú)法直接處理這兩種類型的請(qǐng)求。

解決方案為了解決這個(gè)問(wèn)題,AREX 采用了 base64 編碼技術(shù)在用戶選擇文件時(shí),AREX 會(huì)將二進(jìn)制文件轉(zhuǎn)換為 base64 字符串,然后進(jìn)行傳輸在 Chrome 插件端,AREX 會(huì)將 base64 數(shù)據(jù)進(jìn)行解碼,并用于構(gòu)建實(shí)際的 `fetch` 請(qǐng)求。

這樣可以繞過(guò)直接傳遞二進(jìn)制對(duì)象的限制就這個(gè)問(wèn)題我們采用了 base64 編碼技術(shù),在選擇文件時(shí)我們會(huì)將二進(jìn)制文件轉(zhuǎn)換成 base64 字符串,再進(jìn)行傳輸,Chrome 插件端會(huì)將 base64 數(shù)據(jù)解碼并用于構(gòu)建實(shí)際的 `fetch` 請(qǐng)求。

這個(gè)流程圖描述了將 FormData 中的二進(jìn)制文件轉(zhuǎn)換為 Base64 字符串,并通過(guò) Chrome 插件代理將其轉(zhuǎn)換回文件并進(jìn)行進(jìn)一步處理的過(guò)程form-data binary(A):表示一個(gè)包含二進(jìn)制文件的 FormData 表單數(shù)據(jù)。

FileReader(B):使用 FileReader 對(duì)象來(lái)讀取二進(jìn)制文件readAsDataURL base64 string:FileReader 使用 readAsDataURL 方法將二進(jìn)制文件讀取為 Base64 字符串。

Chrome 插件代理(C):Base64 字符串經(jīng)過(guò)讀取操作后,傳遞給 Chrome 插件代理進(jìn)行進(jìn)一步處理base64 string:表示經(jīng)過(guò) FileReader 讀取二進(jìn)制文件后得到的 Base64 字符串。

Uint8Array(D):在 Chrome 插件代理中,將 Base64 字符串轉(zhuǎn)換為 Uint8ArrayFile(E):使用 Uint8Array 的數(shù)據(jù)創(chuàng)建一個(gè)新的 File 對(duì)象fetch(F):將新創(chuàng)建的 File 對(duì)象通過(guò) fetch 方法或其他方式進(jìn)行進(jìn)一步處理,例如上傳到服務(wù)器或進(jìn)行其他操作。

代碼分析以下是代碼層面的分析:toBase64 函數(shù)接受一個(gè) File 對(duì)象作為參數(shù),并返回一個(gè) Promise 對(duì)象,該 Promise 對(duì)象將解析為表示文件的 Base64 字符串在函數(shù)內(nèi)部,創(chuàng)建了一個(gè) FileReader 對(duì)象。

通過(guò)調(diào)用 reader.readAsDataURL(file) 將文件讀取為 Data URL當(dāng)讀取操作完成時(shí),通過(guò) reader. 事件處理程序?qū)⒆x取結(jié)果解析為字符串,并使用 resolve 將其傳遞給 Promise。

如果發(fā)生錯(cuò)誤,將使用 reject 將錯(cuò)誤傳遞給 Promisebase64ToFile 函數(shù)接受兩個(gè)參數(shù):dataurl(Base64 字符串)和 filename(文件名),并返回一個(gè) File 對(duì)象。

首先,將 dataurl 使用逗號(hào)分割成數(shù)組 arr,如果分割結(jié)果為空,則將其設(shè)為包含一個(gè)空字符串的數(shù)組通過(guò)正則表達(dá)式匹配 arr[0] 中的內(nèi)容,提取出 MIME 類型,即數(shù)據(jù)的類型使用 atob 將 Base64 字符串解碼為二進(jìn)制字符串 bstr。

創(chuàng)建一個(gè)長(zhǎng)度為 n 的 Uint8Array 數(shù)組 u8arr使用循環(huán)遍歷 bstr,將每個(gè)字符的 Unicode 編碼放入 u8arr 中最后,使用 File 構(gòu)造函數(shù)創(chuàng)建并返回一個(gè)新的 File 對(duì)象,其中包含了從 u8arr 中讀取的文件數(shù)據(jù)、文件名和 MIME 類型。

導(dǎo)出 base64ToFile 函數(shù),以便在其他地方使用// 文件轉(zhuǎn)Base64const toBase64 = (file: File): Promise =>new Promise((resolve, reject) => {

const reader = new FileReader; reader.readAsDataURL(file); reader. = => resolve(reader.result as string);

reader. = reject; });// base64轉(zhuǎn)文件functionbase64ToFile(dataurl: string, filename: string) { const arr = dataurl.split(

,) || [ ], mime = arr[0].match(/:(.*?);/)?.[1], bstr = atob(arr[1]); letn = bstr.length; const u8arr = new Uint8Array(n);

while(n--) { u8arr[n] = bstr.charCodeAt(n); } returnnew File([u8arr], filename, { type: mime }); }export

default base64ToFile; ? 快播公司已破產(chǎn)注銷;ChatGPT 之父警告:AI 可能滅絕人類;蘋果官方:618 將開啟全球首次直播|極客頭條 ? FBI 花 3 年暴力破解 iPhone X 密碼,竟成一場(chǎng)空?法院:搜查令已過(guò)期,證據(jù)無(wú)效

? Rust 社區(qū)管理再起“內(nèi)訌”,外部專家遭排擠,核心成員主動(dòng)請(qǐng)辭,立即生效! 返回搜狐,查看更多責(zé)任編輯: