您好,登錄后才能下訂單哦!
使用axios怎么一個自定義適配器adapter?針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
我們在基于 axios 實現額外的數據模塊時,應當與 axios 的模式進行對齊。因此在返回的數據格式上,實現的功能上盡量保持一致。
所有的適配均應當實現為 Promise 方式。
而且,有些功能的實現,axios 將其下放到了適配器中自己進行實現,例如
url 的拼接:即 baseURL 和 url 的拼接,若存在 baseURL 且 url 為相對路徑,則進行拼接,否則直接使用 url;
參數的拼接:若是 get 請求,需要自行將 object 類型拼接為 url 參數的格式并與 url 拼接完成;
這是自己需要實現的兩個基本的工具方法。
這里我們要注意到請求接口正常和異常的格式。
接口正常時:
const result = { status: 200, // 接口的http 狀態 statusText: 'ok', config: 'config', // 傳入的config配置,原樣返回即可,方便在響應攔截器和響應結果中使用 data: {}, // 真實的接口返回結果 };
接口異常時,我們可以看下 axios 源碼中對錯誤信息的處理createError,enhanceError(createError 中調用了 enhanceError),首先會創建一個 error 實例,然后給這個 error 實例添加一個屬性:
module.exports = function enhanceError(error, config, code, request, response) { error.config = config; if (code) { error.code = code; } error.request = request; error.response = response; error.isAxiosError = true; error.toJSON = function toJSON() { return { // Standard message: this.message, name: this.name, // Microsoft description: this.description, number: this.number, // Mozilla fileName: this.fileName, lineNumber: this.lineNumber, columnNumber: this.columnNumber, stack: this.stack, // Axios config: this.config, code: this.code, }; }; return error; };
可以看到,除了正常的錯誤信息外,還加入了很多別的屬性,例如 request, response, config 等。這里我們在自己實現適配器時,最好也要這樣統一編寫,方便更上層的業務層統一處理,避免為單獨的適配器進行特殊處理。
關于 1.1 和 1.2 中的內容,若不進行打包編譯,則需要自己實現。若還要通過 webpack 等打包工具編譯一下的,可以直接引用 axios 中的方法,不用自己實現了,參考官方基于 axios 實現的mock-axios。例如:
import axios from 'axios'; import buildURL from 'axios/lib/helpers/buildURL'; import isURLSameOrigin from 'axios/lib/helpers/isURLSameOrigin'; import btoa from 'axios/lib/helpers/btoa'; import cookies from 'axios/lib/helpers/cookies'; import settle from 'axios/lib/core/settle'; import createError from 'axios/lib/core/createError';
然后直接使用就行了,不用再進行二次開發。
我們不能無限地等待第三方服務的響應,如果第三方服務無響應或者響應時間過長,應當適時的終止掉。在 axios 中,前端使用了XMLHttpRequest,在 node 端使用了http,來實現接口的請求,兩者都有超時的設定,可以設置 timeout 字段來設置超時的時間,自動取消當前的請求。
像有的發起的請求,自己并沒有超時的設定,例如 jsonp,是用創建一個 script 標簽來發起的請求,這個請求必須等到服務器有響應才會終止(成功或者失敗)。這時,就需要我們自己用一個setTimeout來模擬了,但這樣,即使返回給業務層說“超時了,已取消當前請求”,但實際上請求還在,只不過若超過規定時間,只是不再執行對應的成功操作而已。
我們也會有很多并沒有到超時時間,就需要主動取消當前請求的場景,例如在請求返回之前就切換了路由;上次請求還沒響應前,又需要發出新的請求等。都需要主動地取消當前請求。
axios 中已經提供了取消請求的功能,我們只需要按照規則接入即可。我們來看下 XMLHttpRequest 請求器中是怎么取消請求的,在寫自定義請求器時也可以照理使用。
在lib/adapters/xhr.js#L158中:
// 若config中已經配置了cancelToken if (config.cancelToken) { // Handle cancellation // 若在外城執行了取消請求的方法,則這里將當前的請求取消掉 config.cancelToken.promise.then(function onCanceled(cancel) { if (!request) { return; } // xhr中使用abort方法取消當前請求 request.abort(); reject(cancel); // Clean up request request = null; }); }
我們在寫自己的適配器時,也可以將這段拷貝過去,將內部取消的操作更換為自己的即可。
到這里,若把上面的功能都實現了,就已經完成了一個標準的適配器了。
每個人需要的適配器肯定也不一樣,復雜度也不一樣,例如有的想接入小程序的請求,我自己想接入客戶端里提供的數據請求方式等。我們這里只是通過實現一個簡單的jsonp適配器來講解下實現方式。
我們以 es6 的模塊方式來進行開發。所有的實現均在代碼中進行了講解。
// 這里的config是axios里所有的配置 const jsonpAdapter = (config) => { return new Promise((resolve, reject) => { // 是否已取消當前操作 // 因jsonp沒有主動取消請求的方式 // 這里使用 isAbort 來標識 let isAbort = false; // 定時器標識符 let timer = null; // 執行方法的名字, const callbackName = `jsonp${Date.now()}_${Math.random() .toString() .slice(2)}`; // 這里假設已經實現了baseURL和url的拼接方法 const fullPath = buildFullPath(config.baseURL, config.url); // 這里假設已經實現了url和參數的拼接方法 // 不太一樣的地方在于,jsonp需要額外插入一個自己的回調方法 const url = buildURL( fullPath, { ...config.params, ...{ [config.jsonpCallback || 'callback']: callbackName }, }, config.paramsSerializer ); // 創建一個script標簽 let script = document.createElement('script'); // 成功執行操作后 function remove() { if (script) { script.onload = script.onerror = null; // 移除script標簽 if (script.parentNode) { script.parentNode.removeChild(script); } // 取消定時器 if (timer) { clearTimeout(timer); } script = null; } } // 成功請求后 window[callbackName] = (data) => { // 若已需要請求,則不再執行 if (isAbort) { return; } // 返回的格式 const response = { status: 200, statusText: 'ok', config, request: script, data: data, }; remove(); // 實際上這里上一個settle操作,會額外判斷是否是合理的status狀態 // 若我們在config.validateStatus中設置404是合理的,也會進入到resolve狀態 // 但我們這里就不實現這個了 // settle(resolve, reject, response); resolve(response); }; // 請求失敗 script.onerror = function (error) { remove(); reject(createError('Network Error', config, 404)); }; // 若設置了超時時間 if (config.timeout) { timer = setTimeout(function () { remove(); // 取消當前操作 isAbort = true; reject( createError( 'timeout of ' + config.timeout + 'ms exceeded', config, 405 ) ); }, config.timeout); } // 若定義了取消操作 if (config.cancelToken) { config.cancelToken.promise.then(function () { if (!script) { return; } remove(); isAbort = true; reject(createError('Cancel Error', config, 404)); }); } script.src = url; const target = document.getElementsByTagName('script')[0] || document.head; target.parentNode && target.parentNode.insertBefore(script, target); }); }; export default jsonpAdapter;
axios 的 config 提供了 adapter 字段讓我們插入自己的適配器。使用自定義適配器又有兩種情況:
1.完全只使用自定義的適配器;
2.在某種情況下使用自定義適配器,其他情況時還是使用 axios 自己的適配器。
第 1 種情況還好,只需要 return 自己適配器返回的結果結果即可;而第 2 種情況中,則有個小坑需要踩一下,我們這里也只講解下第 2 種情況。我要把剛才實現的 jsonp 適配器添加到 axios 中,并且只在參數有format=jsonp時才調用該適配器,其他還是用的 axios 提供的適配器。
import Axios from 'axios'; import jsonpAdapter from './jsonpAdater'; const request = Axios.create({ adapter: (config) => { if (config?.params?.format === 'jsonp') { return jsonpAdapter(config); } // 這里需要將config.adapter設置為空 // 否則會造成無限循環 return defaultAxios({ ...config, ...{ adapter: undefined } }); }, });
使用自定義的適配器 jsonp 發起請求。
// 使用自定義的適配器jsonp發起請求 var options = { params: { format: 'jsonp', }, }; request( 'https://api.prize.qq.com/v1/newsapp/answer/share/oneQ?qID=506336', options ) .then(function (response) { console.log('jsonp response', response); }) .catch(function (error) { console.error('jsonp error', error); });
使用 axios 默認的適配器發起請求。
// 使用axios默認的適配器發起請求 request('https://api.prize.qq.com/v1/newsapp/answer/share/oneQ?qID=506336') .then(function (response) { console.log('axios response', response); }) .catch(function (error) { console.error('axios error', error); });
關于使用axios怎么一個自定義適配器adapter問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。