1. 程式人生 > >基於小程式請求介面 wx.request 封裝的類 axios 請求

基於小程式請求介面 wx.request 封裝的類 axios 請求

# 基於小程式請求介面 wx.request 封裝的類 axios 請求 ## Introduction - wx.request 的配置、axios 的呼叫方式 - [原始碼戳我](https://github.com/T-Macgrady/blog/tree/master/request) ## feature - 支援 wx.request 所有配置項 - 支援 axios 呼叫方式 - 支援 自定義 baseUrl - 支援 自定義響應狀態碼對應 resolve 或 reject 狀態 - 支援 對響應(resolve/reject)分別做統一的額外處理 - 支援 轉換請求資料和響應資料 - 支援 請求快取(記憶體或本地快取),可設定快取標記、過期時間 ## use ### app.js @onLaunch ```javascript import axios form 'axios' axios.creat({ header: { content-type': 'application/x-www-form-urlencoded; charset=UTF-8' }, baseUrl: 'https://api.baseurl.com', ... }); ``` ### page.js ```javascript axios .post("/url", { id: 123 }) .then((res) => { console.log(response); }) .catch((err) => { console.log(err); }); ``` ## API ```javascript axios(config) - 預設get axios(url[, config]) - 預設get axios.get(url[, config]) axios.post(url[, data[, config]]) axios.cache(url[, data[, config]]) - 快取請求(記憶體) axios.cache.storage(url[, data[, config]]) - 快取請求(記憶體 & local storage) axios.creat(config) - 初始化定製配置,覆蓋預設配置 ``` ## config 預設配置項說明 ```javascript export default { // 請求介面地址 url: undefined, // 請求的引數 data: {}, // 請求的 header header: "application/json", // 超時時間,單位為毫秒 timeout: undefined, // HTTP 請求方法 method: "GET", // 返回的資料格式 dataType: "json", // 響應的資料型別 responseType: "text", // 開啟 http2 enableHttp2: false, // 開啟 quic enableQuic: false, // 開啟 cache enableCache: false, /** 以上為wx.request的可配置項,參考 https://developers.weixin.qq.com/miniprogram/dev/api/network/request/wx.request.html */ /** 以下為wx.request沒有的新增配置項 */ // {String} baseURL` 將自動加在 `url` 前面,可以通過設定一個 `baseURL` 便於傳遞相對 URL baseUrl: "", // {Function} (同axios的validateStatus)定義對於給定的HTTP 響應狀態碼是 resolve 或 reject promise 。如果 `validateStatus` 返回 `true` (或者設定為 `null` 或 `undefined`),promise 將被 resolve; 否則,promise 將被 reject validateStatus: undefined, // {Function} 請求引數包裹(類似axios的transformRequest),通過它可統一補充請求引數需要的額外資訊(appInfo/pageInfo/場景值...),需return data transformRequest: undefined, // {Function} resolve狀態下響應資料包裹(類似axios的transformResponse),通過它可統一處理響應資料,需return res transformResponse: undefined, // {Function} resolve狀態包裹,通過它可做介面resolve狀態的統一處理 resolveWrap: undefined, // {Function} reject狀態包裹,通過它可做介面reject狀態的統一處理 rejectWrap: undefined, // {Boolean} _config.useCache 是否開啟快取 useCache: false, // {String} _config.cacheName 快取唯一key值,預設使用url&data生成 cacheName: undefined, // {Boolean} _config.cacheStorage 是否開啟本地快取 cacheStorage: false, // {Any} _config.cacheLabel 快取標誌,請求前會對比該標誌是否變化來決定是否使用快取,可用useCache替代 cacheLabel: undefined, // {Number} _config.cacheExpireTime 快取時長,計算快取過期時間,單位-秒 cacheExpireTime: undefined, }; ``` ## 實現 ### axios.js ```javascript import Axios from "./axios.class.js"; // 建立axios例項 const axiosInstance = new Axios(); // 獲取基礎請求axios const { axios } = axiosInstance; // 將例項的方法bind到基礎請求axios上,達到支援請求別名的目的 axios.creat = axiosInstance.creat.bind(axiosInstance); axios.get = axiosInstance.get.bind(axiosInstance); axios.post = axiosInstance.post.bind(axiosInstance); axios.cache = axiosInstance.cache.bind(axiosInstance); axios.cache.storage = axiosInstance.storage.bind(axiosInstance); ``` ### Axios class #### 初始化 - defaultConfig 預設配置,即 defaults.js - axios.creat 使用者配置覆蓋預設配置 - 注意配置初始化後 mergeConfig 不能被汙染,config 需通過引數傳遞 ```javascript constructor(config = defaults) { this.defaultConfig = config; } creat(_config = {}) { this.defaultConfig = mergeConfig(this.defaultConfig, _config); } ``` #### 請求別名 - axios 相容 axios(config) 或 axios(url[, config]); - 別名都只是 config 合併,最終都通過 axios.requst()發起請求; ```javascript axios($1 = {}, $2 = {}) { let config = $1; // 相容axios(url[, config])方式 if (typeof $1 === 'string') { config = $2; config.url = $1; } return this.request(config); } post(url, data = {}, _config = {}) { const config = { ..._config, url, data, method: 'POST', }; return this.request(config); } ``` #### 請求方法 \_request 請求配置預處理 - 實現 baseUrl - 實現 transformRequest(轉換請求資料) ```javascript _request(_config = {}) { let config = mergeConfig(this.defaultConfig, _config); const { baseUrl, url, header, data = {}, transformRequest } = config; const computedConfig = { header: { 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8', ...header, }, ...(baseUrl && { url: combineUrl(url, baseUrl), }), ...(transformRequest && typeof transformRequest === 'function' && { data: transformRequest(data), }), }; config = mergeConfig(config, computedConfig); return wxRequest(config); } ``` #### wx.request 發起請求、處理響應 - 實現 validateStatus(狀態碼對映 resolve) - 實現 transformResponse(轉換響應資料) - 實現 resolveWrap、rejectWrap(響應狀態處理) ```javascript export default function wxRequest(config) { return new Promise((resolve, reject) => { wx.request({ ...config, success(res) { const { resolveWrap, rejectWrap, transformResponse, validateStatus, } = config; if ((validateStatus && validateStatus(res)) || ifSuccess(res)) { const _resolve = resolveWrap ? resolveWrap(res) : res; return resolve( transformResponse ? transformResponse(_resolve) : _resolve ); } return reject(rejectWrap ? rejectWrap(res) : res); }, fail(res) { const { rejectWrap } = config; reject(rejectWrap ? rejectWrap(res) : res); }, }); }); } ``` ### 請求快取的實現 - 預設使用記憶體快取,可配置使用 localStorage - 封裝了 Storage 與 Buffer 類,與 Map 介面一致:get/set/delete - 支援快取標記&過期時間 - 快取唯一 key 值,預設使用 url&data 生成,無需指定 ```javascript import Buffer from '../utils/cache/Buffer'; import Storage from '../utils/cache/Storage'; import StorageMap from '../utils/cache/StorageMap'; /** * 請求快取api,緩存於本地快取中 */ storage(url, data = {}, _config = {}) { const config = { ..._config, url, data, method: 'POST', cacheStorage: true, }; return this._cache(config); } /** * 請求快取 * @param {Object} _config 配置 * @param {Boolean} _config.useCache 是否開啟快取 * @param {String} _config.cacheName 快取唯一key值,預設使用url&data生成 * @param {Boolean} _config.cacheStorage 是否開啟本地快取 * @param {Any} _config.cacheLabel 快取標誌,請求前會對比該標誌是否變化來決定是否使用快取,可用useCache替代 * @param {Number} _config.cacheExpireTime 快取時長,計算快取過期時間,單位-秒 */ _cache(_config) { const { url = '', data = {}, useCache = true, cacheName: _cacheName, cacheStorage, cacheLabel, cacheExpireTime, } = _config; const computedCacheName = _cacheName || `${url}#${JSON.stringify(data)}`; const cacheName = StorageMap.getCacheName(computedCacheName); // return buffer if (useCache && Buffer.has(cacheName, cacheLabel)) { return Buffer.get(cacheName); } // return storage if (useCache && cacheStorage) { if (Storage.has(cacheName, cacheLabel)) { const data = Storage.get(cacheName); // storage => buffer Buffer.set( cacheName, Promise.resolve(data), cacheExpireTime, cacheLabel ); return Promise.resolve(data); } } const curPromise = new Promise((resolve, reject) => { const handleFunc = (res) => { // do storage if (useCache && cacheStorage) { Storage.set(cacheName, res, cacheExpireTime, cacheLabel); } return res; }; this._request(_config) .then((res) => { resolve(handleFunc(res)); }) .catch(reject); }); // do buffer Buffer.set(cacheName, curPromise, cacheExpireTime, cacheLabel); return curPromise;