您好,登錄后才能下訂單哦!
本篇文章為大家展示了Ant Design Pro 5 網(wǎng)絡(luò)請(qǐng)求和錯(cuò)誤處理是怎樣的,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。
Ant Design Pro 5 的網(wǎng)絡(luò)請(qǐng)求有點(diǎn)復(fù)雜,只看文檔不閱讀源碼搞不清楚到底發(fā)生了什么事情。涉及到fetch umi-request @umijs/plugin-request Ant Design Pro 5相關(guān)代碼。
代替XMLHttpRequest的訪(fǎng)問(wèn)和操縱HTTP的技術(shù)。fetch最大的問(wèn)題是,只有在發(fā)生網(wǎng)絡(luò)故障時(shí)或請(qǐng)求被阻止時(shí),才拋出異常;而對(duì)于 HTTP 狀態(tài)碼為 404 或 500 之類(lèi)的情況,會(huì)認(rèn)為是正常的響應(yīng),并不會(huì)拋出異常。
參考資料:Fetch API
基于 fetch 封裝,提供諸如緩存、超時(shí)、字符編碼處理、錯(cuò)誤處理等功能。其中錯(cuò)誤處理與開(kāi)發(fā)緊密關(guān)聯(lián)。
為了解決fetch在非成功狀態(tài)碼下,不拋出異常的情況,umi-request會(huì)判斷HTTP狀態(tài)碼是否為2xx;如果不是,則會(huì)拋出異常。并且對(duì)fetch自己拋出的異常也進(jìn)行了處理,加上了更多信息,便于后續(xù)的處理。
/src/middleware/parseResponse.js
... .then(body => { ... if (copy.status >= 200 && copy.status < 300) { // 提供源response, 以便自定義處理 if (getResponse) { ctx.res = { data: body, response: copy }; return; } ctx.res = body; return; } throw new ResponseError(copy, 'http error', body, req, 'HttpError'); }) .catch(e => { if (e instanceof RequestError || e instanceof ResponseError) { throw e; } // 對(duì)未知錯(cuò)誤進(jìn)行處理 const { req, res } = ctx; e.request = e.request || req; e.response = e.response || res; e.type = e.type || e.name; e.data = e.data || undefined; throw e; }); ...
參考資料:umi-request
@umijs/plugin-request則在umi-request上又進(jìn)行了封裝。umi-request提供了錯(cuò)誤處理機(jī)制,@umijs/plugin-request則提供了常規(guī)的錯(cuò)誤處理方法,并約定了服務(wù)器返回響應(yīng)的數(shù)據(jù)格式。還提供了useRequest。
需要特別注意的是,引用request時(shí),要引用@umijs/plugin-request,而不是umi-request,否則會(huì)發(fā)現(xiàn)request的行為與@umijs/plugin-request文檔描述的不一致。具體代碼如下:
// 引用 umi-request 的 request。錯(cuò)誤?。?! import request from 'umi-request'; // 引用 @umijs/plugin-request 的 reqeust。正確。 import {request} from 'umi';
約定服務(wù)器返回的數(shù)據(jù)格式如下:
interface ErrorInfoStructure { success: boolean; // if request is success data?: any; // response data errorCode?: string; // code for errorType errorMessage?: string; // message display to user showType?: number; // error display type: 0 silent; 1 message.warn; 2 message.error; 4 notification; 9 page traceId?: string; // Convenient for back-end Troubleshooting: unique request ID host?: string; // onvenient for backend Troubleshooting: host of current access server }
對(duì)于服務(wù)器返回的數(shù)據(jù)于這個(gè)格式不一致的,可以在A(yíng)nt Design Pro 5/src/app.tsx通過(guò)配置進(jìn)行適配。但此適配只作用于錯(cuò)誤處理,并影響接口返回的數(shù)據(jù)。所以在使用useRequest時(shí),這個(gè)適配并沒(méi)有用。
export const request: RequestConfig = { errorConfig: { adaptor: (resData) => { return { ...resData, success: resData.ok, errorMessage: resData.message, }; }, }, };
返回的數(shù)據(jù)格式中有success字段,用于描述請(qǐng)求是否成功。而umi-request對(duì)于http 2xx以外的響應(yīng)都會(huì)拋出異常,此處的success又有何用呢?答案是http 2xx的請(qǐng)求也可以返回success:false從而人為的拋出一個(gè)異常。
但我們并不建議這樣做,錯(cuò)誤的請(qǐng)求應(yīng)該返回http 2xx以外的響應(yīng),由umi-request自動(dòng)拋出一個(gè)異常。所以適配數(shù)據(jù)結(jié)構(gòu)時(shí),success可始終為true。
/umijs/plugins/blob/master/packages/plugin-request/src/request.ts
... const errorAdaptor = requestConfig.errorConfig?.adaptor || (resData => resData); ... // 中間件統(tǒng)一錯(cuò)誤處理 // 后端返回格式 { success: boolean, data: any } // 按照項(xiàng)目具體情況修改該部分邏輯 requestMethodInstance.use(async (ctx, next) => { ... const errorInfo = errorAdaptor(resData, ctx); if (errorInfo.success === false) { // 拋出錯(cuò)誤到 errorHandler 中處理 const error: RequestError = new Error(errorInfo.errorMessage); error.name = 'BizError'; error.data = resData; error.info = errorInfo; throw error; } });
如服務(wù)器按照格式返回?cái)?shù)據(jù),則一切較為順利。但即使是正常的響應(yīng),也必須把數(shù)據(jù)包裝在data字段里,這樣在后端和前端都會(huì)感覺(jué)有些別扭。一般希望正常響應(yīng)直接返回?cái)?shù)據(jù),只有在發(fā)生錯(cuò)誤是,才返回類(lèi)似的數(shù)據(jù)格式。
錯(cuò)誤處理時(shí),也會(huì)調(diào)用上述的數(shù)據(jù)格式適配,所以并不是success不為false數(shù)據(jù)適配就無(wú)用了。主要從數(shù)據(jù)適配里獲得showType errorMessage errorCode。
/umijs/plugins/blob/master/packages/plugin-request/src/request.ts
const errorAdaptor = requestConfig.errorConfig?.adaptor || (resData => resData); requestMethodInstance = extend({ errorHandler: (error: RequestError) => { // @ts-ignore if (error?.request?.options?.skipErrorHandler) { throw error; } let errorInfo: ErrorInfoStructure | undefined; if (error.name === 'ResponseError' && error.data && error.request) { const ctx: Context = { req: error.request, res: error.response, }; errorInfo = errorAdaptor(error.data, ctx); error.message = errorInfo?.errorMessage || error.message; error.data = error.data; error.info = errorInfo; } errorInfo = error.info; if (errorInfo) { const errorMessage = errorInfo?.errorMessage; const errorCode = errorInfo?.errorCode; const errorPage = requestConfig.errorConfig?.errorPage || DEFAULT_ERROR_PAGE; switch (errorInfo?.showType) { case ErrorShowType.SILENT: // do nothing break; case ErrorShowType.WARN_MESSAGE: message.warn(errorMessage); break; case ErrorShowType.ERROR_MESSAGE: message.error(errorMessage); break; case ErrorShowType.NOTIFICATION: notification.open({ message: errorMessage, }); break; case ErrorShowType.REDIRECT: // @ts-ignore history.push({ pathname: errorPage, query: { errorCode, errorMessage }, }); // redirect to error page break; default: message.error(errorMessage); break; } } else { message.error(error.message || 'Request error, please retry.'); } throw error; }, ...requestConfig, });
數(shù)據(jù)類(lèi)型中showType字段的值有以下幾個(gè),配合錯(cuò)誤處理方法,可以針對(duì)不同錯(cuò)誤類(lèi)型以不同的方式顯示。
export enum ErrorShowType { SILENT = 0, // 不提示錯(cuò)誤 WARN_MESSAGE = 1, // 警告信息提示 ERROR_MESSAGE = 2, // 錯(cuò)誤信息提示 NOTIFICATION = 4, // 通知提示 REDIRECT = 9, // 頁(yè)面跳轉(zhuǎn) }
安裝前面的數(shù)據(jù)格式約定,useRequest默認(rèn)從響應(yīng)數(shù)據(jù)里的data字段里獲取數(shù)據(jù)。如果服務(wù)器端是直接返回?cái)?shù)據(jù),則需要在A(yíng)nt Design Pro/config/config.ts配置:
request: { dataField: '', }
需要注意,前面做的數(shù)據(jù)適配在useRequest里是無(wú)效的,不要認(rèn)為做了數(shù)據(jù)適配就萬(wàn)事大吉了。當(dāng)然服務(wù)器按照前面約定的數(shù)據(jù)格式返回?cái)?shù)據(jù)就沒(méi)這些煩惱了。
Ant Design對(duì)分頁(yè)數(shù)據(jù)的結(jié)構(gòu)也有規(guī)定。
{ list: [], current?: number, pageSize?: number, total?: number, }
如不符合這個(gè)格式,可以在useRequest的formatResult進(jìn)行配置。如:
const { data, loading } = useRequest(() => { return services.getUserList('/api/test'); },{ formatResult: (result) => { return ... } });
參考資料:
@umijs/plugin-request文檔
@umijs/plugin-request源碼
提供了自定義錯(cuò)誤處理方法,和自定義數(shù)據(jù)格式的接口。默認(rèn)的演示代碼中,覆蓋了@umijs/plugin-request的錯(cuò)誤處理方法。如未注意到這點(diǎn),則會(huì)迷惑于A(yíng)nt Design Pro 5的錯(cuò)誤處理行為與@umijs/plugin-request文檔描述的并不一致,前面所述的錯(cuò)誤顯示類(lèi)型完全無(wú)效。
Ant Design Pro/config/config.ts
const errorHandler = (error: ResponseError) => { const { response } = error; if (response && response.status) { const errorText = codeMessage[response.status] || response.statusText; const { status, url } = response; notification.error({ message: `請(qǐng)求錯(cuò)誤 ${status}: ${url}`, description: errorText, }); } if (!response) { notification.error({ description: '您的網(wǎng)絡(luò)發(fā)生異常,無(wú)法連接服務(wù)器', message: '網(wǎng)絡(luò)異常', }); } throw error; }; export const request: RequestConfig = { errorHandler, };
上述內(nèi)容就是Ant Design Pro 5 網(wǎng)絡(luò)請(qǐng)求和錯(cuò)誤處理是怎樣的,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。