antd request 通过jsessionid传参数_Umi-request源码阅读
最近參照antd-pro腳手架進行開發(fā),因此接觸到了umi-request。
umijs/umi-request?github.comumi-request對fetch進行了封裝,簡化了api的使用,結合了fetch和axios的特點,具體可參照umi-request的readme介紹。
文件結構
核心文件夾為src文件夾,內含
- lib文件夾為修改后的fetch.js;
- defaultInterceptor.js用于注冊攔截器;
- index.js是外部調用的入口文件;
- request.js提供request實例;
- utils.js定義了處理緩存、請求異常、響應異常、處理gbk、json語法分析的功能類;
- wrapped-fetch.js從文件名可以看出來為封裝fetch,實現(xiàn)更新版數(shù)據(jù)的傳遞;
- wrapped-rpc.js從文件可以看出封裝了rpc通信,待實現(xiàn);
代碼分析
原始代碼里含的注釋基本上已經很全面了
defaultInterceptor.js
功能有:數(shù)據(jù)提交方式簡化/針對常見兩種數(shù)據(jù)傳輸格式補全文件頭“Accept: 'application/json', 'Content-Type': 'application/json(或者x-www-form-urlencoded);charset=UTF-8'”/url 參數(shù)自動序列化
主要是對傳入的url和option進行格式化的處理,以便后續(xù)的fetch.js進行處理。關于option的新增參數(shù)參見request.js。export default (url, originOptions = {}) => {const options = { ...originOptions };// 默認get, 兼容method大小寫let method = options.method || 'get';method = method.toLowerCase();if (method === 'post' || method === 'put' || method === 'patch' || method === 'delete') {// requestType 簡寫默認值為 jsonconst { requestType = 'json', data } = options;// 數(shù)據(jù)使用類axios的新字段data, 避免引用后影響舊代碼, 如將body stringify多次if (data) {const dataType = Object.prototype.toString.call(data);if (dataType === '[object Object]' || dataType === '[object Array]') {if (requestType === 'json') {options.headers = {Accept: 'application/json','Content-Type': 'application/json;charset=UTF-8',...options.headers,};options.body = JSON.stringify(data);} else if (requestType === 'form') {options.headers = {Accept: 'application/json','Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',...options.headers,};options.body = stringify(data);}} else {// 其他 requestType 自定義headeroptions.headers = {Accept: 'application/json',...options.headers,};options.body = data;}}}// 支持類似axios 參數(shù)自動拼裝, 其他method也可用, 不沖突.if (options.params && Object.keys(options.params).length > 0) {const str = url.indexOf('?') !== -1 ? '&' : '?';url = `${url}${str}${stringify(options.params)}`;}return {url,options,}; };
fetch.js
主要是定義了request和response攔截器。
攔截器,在AOP(Aspect-Oriented Programming)中用于在某個方法或字段被訪問之前,進行攔截,然后在之前或之后加入某些操作。可以對http請求進行批量處理。import 'whatwg-fetch'; import defaultInterceptor from '../defaultInterceptor';const requestInterceptors = []; export const responseInterceptors = [];function fetch(url, options = {}) {if (typeof url !== 'string') throw new Error('url MUST be a string');// 執(zhí)行 request 的攔截器,使用defaultInterceptor,依據(jù)handler方式對url,option進行處理requestInterceptors.concat([defaultInterceptor]).forEach(handler => {const ret = handler(url, options);url = ret.url || url;options = ret.options || options;});// 將 method 改為大寫options.method = options.method ? options.method.toUpperCase() : 'GET';// 請求數(shù)據(jù)let response = window.fetch(url, options);// 執(zhí)行 response 的攔截器,依據(jù)handler方式對url,option進行處理responseInterceptors.forEach(handler => {response = response.then(res => handler(res, options));});return response; } // 支持攔截器,參考 axios 庫的寫法: https://github.com/axios/axios#interceptors fetch.interceptors = {request: {use: handler => {requestInterceptors.push(handler);},},response: {use: handler => {responseInterceptors.push(handler);},}, };export default fetch;utils.js
定義了處理緩存(Mapcache)、請求異常(RequestError)、響應異常(ResponseError)、處理gbk(readerGBK)、json語法轉換(safeJsonParse)的功能類;
- 處理緩存
options.maxCache是option的extend參數(shù),可以在封裝umi-request時指定,
如antd-pro. const request = extend({maxCache: 50,});實現(xiàn)變量的獲取、變量刪除、緩存清空、value存入緩存(其中key json化后為關鍵字)
export class MapCache {constructor(options) {this.cache = new Map();this.timer = {};this.maxCache = options.maxCache || 0;}get(key) {return this.cache.get(JSON.stringify(key));}set(key, value, ttl = 60000) {// 如果超過最大緩存數(shù), 刪除頭部的第一個緩存.if (this.maxCache > 0 && this.cache.size >= this.maxCache) {const deleteKey = [...this.cache.keys()][0];this.cache.delete(deleteKey);if (this.timer[deleteKey]) {clearTimeout(this.timer[deleteKey]);}}const cacheKey = JSON.stringify(key);this.cache.set(cacheKey, value);if (ttl > 0) {this.timer[cacheKey] = setTimeout(() => {this.cache.delete(cacheKey);delete this.timer[cacheKey];}, ttl);}}delete(key) {const cacheKey = JSON.stringify(key);delete this.timer[cacheKey];return this.cache.delete(cacheKey);}clear() {this.timer = {};return this.cache.clear();} }在wrapped-fetch.js中調用
_wrappedCache(instance, useCache) {if (useCache) {const { params, ttl } = this.options;//url請求參數(shù)params,和緩存時長ttl為option傳入參數(shù)return instance.then(response => {// 只緩存狀態(tài)碼為 200的數(shù)據(jù)if (response.status === 200) {const copy = response.clone();copy.useCache = true;//this.cache為通過request.js調用傳入的參數(shù)const mapCache = new MapCache(initOptions);this.cache.set({ url: this.url, params }, copy, ttl);}return response;});} else {return instance;} }- 請求異常
在wrapped-fetch.js中如此使用,用于輸出超時信息,其中timeout為option傳入參數(shù)。需要注意的是超時后客戶端雖然返回超時, 但api請求不會斷開, 寫操作慎用。
return Promise.race([new Promise((_, reject) =>setTimeout(() => reject(new RequestError(`timeout of ${timeout}ms exceeded`)), timeout)),instance, ]);- 響應異常
在wrapped-fetch.js中調用,示例,當異常時拋出異常
catch (e) {throw new ResponseError(response, e.message);}- 支持gbk并進行json格式的轉換
判斷返回的數(shù)據(jù)時表示gbk編碼的,如果是,將數(shù)據(jù)以gbk格式讀入,然后再利用safeJsonParse轉化為json格式
export function readerGBK(file) {return new Promise((resolve, reject) => {const reader = new FileReader();reader.onload = () => {resolve(reader.result);};reader.onerror = reject;reader.readAsText(file, 'GBK'); // setup GBK decoding}); }export function safeJsonParse(data) {try {return JSON.parse(data);} catch (e) {} // eslint-disable-linereturn data; }wrappedfetch.js
核心部分,基于fetch進行數(shù)據(jù)交互
一個 Promise 就是一個對象,它代表了一個異步操作的最終完成或者失敗,通過 .then() 形式添加的回調函數(shù),連續(xù)執(zhí)行兩個或者多個異步操作(鏈式調用,多個then,一個catch接收異常)。一個 Promise有以下幾種狀態(tài):
- pending: 初始狀態(tài),既不是成功,也不是失敗狀態(tài)。
- fulfilled: 意味著操作成功完成。
- rejected: 意味著操作失敗。
當其中任一種情況出現(xiàn)時,Promise 對象的 then 方法綁定的處理方法(handlers )就會被調用(then方法包含兩個參數(shù):onfulfilled 和 onrejected,它們都是 Function 類型。當Promise狀態(tài)為fulfilled時,調用 then 的 onfulfilled 方法,當Promise狀態(tài)為rejected時,調用 then 的 onrejected 方法。
Promise.resolve(value)方法返回一個以給定值解析后的Promise 對象。但如果這個值是個thenable(即帶有then方法),返回的promise會“跟隨”這個thenable的對象,采用它的最終狀態(tài)(指resolved/rejected/pending/settled);如果傳入的value本身就是promise對象,則該對象作為Promise.resolve方法的返回值返回;否則以該值為成功狀態(tài)返回promise對象。
Promise.reject(reason)返回一個狀態(tài)為失敗的Promise對象,并將給定的失敗信息傳遞給對應的處理方法
export default class WrappedFetch {constructor(url, options, cache) {this.cache = cache;//cache是MapCache的實例this.url = url;this.options = options;this._addfix();return this._doFetch();}_doFetch() {//如果使用cache,只有在option的method是get且useCache為true時使用cacheif (useCache) {let response = this.cache.get({url: this.url,params: this.options.params,});if (response) {response = response.clone();let instance = Promise.resolve(response);responseInterceptors.forEach(handler => {instance = instance.then(res => handler(res, this.options));});return this._parseResponse(instance, true);}}let instance = fetch(this.url, this.options);// 處理超時instance = this._wrappedTimeout(instance);// 處理緩存 1.只有get 2.同時參數(shù)cache為true 才緩存instance = this._wrappedCache(instance, useCache);// 返回解析好的數(shù)據(jù)return this._parseResponse(instance);}//對url進行自動序列化,添加前綴和后綴_addfix() {} //調用RequestError,在超時后輸出信息_wrappedTimeout(instance) {}//調用MapCache,在用戶使用usecache時將response復制到擦車中,并設置緩存時間_wrappedCache(instance, useCache) {}//處理返回類型, 并解析數(shù)據(jù),如果編碼方式時gbk則利用readerGBK和safeJsonParse進行轉化,在讀取response時,加入responseError處理_parseResponse(instance, useCache = false) {}//處理錯誤_handleError({ reject, resolve }, error) {} }request.js
option里支持的參數(shù)有:(較fetch增加的)
* @param {string} requestType post類型, 用來簡化寫content-Type, 默認json* @param {*} data post數(shù)據(jù)
* @param {object} params query參數(shù)
* @param {string} responseType 服務端返回的數(shù)據(jù)類型, 用來解析數(shù)據(jù), 默認json
* @param {boolean} useCache 是否使用緩存,只有get時有效, 默認關閉, 啟用后如果命中緩存, response中有useCache=true. 另: 內存緩存, 刷新就沒。一個簡單的Map cache, 提供session local map三種前端cache方式.
* @param {number} ttl 緩存生命周期, 默認60秒, 單位毫秒
* @param {number} timeout 超時時長, 默認未設, 單位毫秒
* @param {boolean} getResponse 是否獲取response源
* @param {function} errorHandler 錯誤處理
* @param {string} prefix 前綴
* @param {string} suffix 后綴
* @param {string} charset 字符集, 默認utf8
extend里支持的參數(shù)有:
* @param {number} maxCache 最大緩存數(shù)* @param {string} prefix url前綴
* @param {function} errorHandler 統(tǒng)一錯誤處理方法
* @param {object} headers 統(tǒng)一的headers
method包括:'get', 'post', 'delete', 'put', 'patch','rpc'。其中,'get', 'post', 'delete', 'put', 'patch'屬于REST風格,是http協(xié)議的一種直接應用,默認基于json作為傳輸格式,使用簡單,學習成本低效率高。RPC是指遠程過程調用直觀說法就是A通過網絡調用B的過程方法,是分布式系統(tǒng)中常見的方法。
- GET操作是安全且等冪的。所謂安全是指不管進行多少次操作,資源的狀態(tài)都不會改變。
- PUT,DELETE操作是冪等的。所謂冪等是指不管進行多少次操作,結果都一樣。比如我用PUT修改一篇文章,然后在做同樣的操作,每次操作后的結果并沒有不同,DELETE也是一樣。
- POST操作既不是安全的,也不是冪等的,比如常見的POST重復加載問題:當我們多次發(fā)出同樣的POST請求后,其結果是創(chuàng)建出了若干的資源。
- PATCH新引入的,是對PUT方法的補充,用來對已知資源進行局部更新。在沒有patch之前,我們都是用put進行更新操作,這時候我們的接口中通常會有一個邏輯規(guī)則,如:如果對象的的一個字符屬性為NULL,那么就是不更新該屬性(字段)值,如果對象的字符屬性是“”,那么就更新該屬性(字段)的值,通過這種方式來避免全部覆蓋的操作。現(xiàn)在有了patch就解決了這種判斷,在put接口中不管屬性是不是null,都進行更新,在patch接口中就對非null的進行更新
使用示例
通過extend進行簡單封裝,參照antd-pro,dva數(shù)據(jù)流處理方式。
import { extend } from 'umi-request'; ...... const request = extend({errorHandler, // 默認錯誤處理函數(shù)credentials: 'include', // 默認請求是否帶上cookie// useCache: false,// maxCache: 50, }); export default request;后續(xù)在api.js中的使用
import request from '@/utils/request'; //get請求 export async function function1({ classId }) {return request(`/api/classes/${classId}/teachers/`);} //post請求 export async function function2({ classId }) {return request.post('/api/classes/${classId}/teachers/', { data: {foo: 'bar'}});} // 使用緩存 export async function function3({ classId }) {return request(`/api/classes/${classId}/teachers/`, { useCache: true, ttl: 10000 });}每一個頁面對應的model中,可以通過下面的方式進行使用
* fetchBasic({ classId }, { call, put }) {//利用call方式調用api.js中聲明的function1 const response = yield call(fuction1, classId);//對接收到的response進行處理yield put({type: 'saveResponse',//reducers中對應的處理方法payload: response}); },特點
- url 參數(shù)自動序列化
- post 數(shù)據(jù)提交方式簡化
- response 返回處理簡化
- api 超時支持
- api 請求緩存支持
- 支持處理 gbk
- 類 axios 的 request 和 response 攔截器(interceptors)支持
總結
以上是生活随笔為你收集整理的antd request 通过jsessionid传参数_Umi-request源码阅读的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 只有15个字符!世界上第一条短信首次被拍
- 下一篇: 插入始终是1_插入式电磁流量计特点与应用