基於 TS 實現 axios(三)

這一小節,主要是把異常的處理加上

處理錯誤

網絡錯誤

就在你發送 Ajax 請求的地方,new 出來的 XMLHttpRequest 有一個 onerror 的方法,把你的方法掛上去就可以了。

request.onerror = function handleError() {
    reject(new Error('Network Error'));
} 

超時錯誤

同樣的,在new 出來的 XMLHttpRequest 有一個 ontimeout 的方法,把你的方法掛上去就可以了。

if(timeout) request.timeout = timeout;	// timeout 是可選的

request.ontimeout = function handleTimeout() {
    reject(new Error(`Timeout of ${timeout} ms exceeded`));
}

其他錯誤

response.status 在 [200,300) 之間,就表明請求成功,否則就表示錯誤。以下這個函數是放在 onreadystatechange 函數的最後來進行處理。

function handleResponse(response: AxiosResponse) : void{
    if(response.status >= 200 && response.status < 300) {
    	reslove(response);
    } else {
    	reject(new Error(`Request failed with status code ${response.status}`));
    }
}

更加詳盡的錯誤信息

這個其實就是構造函數

import {AxiosRequestConfig,AxiosResponse} from '../types';

export class AxiosError extends Error {
    isAxiosError: boolean
    config: AxiosRequestConfig
    code?: string|null
    request?:any
    response?:AxiosResponse
    constructor(
        message:string,
        config:AxiosRequestConfig,
        code?: string|null,
        request?:any,
        response?: AxiosResponse,

    ){
        super(message);
        this.config = config;
        this.code = code;
        this.request = request;
        this.response = response;
        this.isAxiosError = true;
        Object.setPrototypeOf(this,AxiosError.prototype);
    }
}

export function createError(
    message:string,
    config:AxiosRequestConfig,
    code?: string|null,
    request?:any,
    response?: AxiosResponse,
) {
    return new AxiosError(message,config,code,request,response);
}

在之前使用 new Error() 的,都改成 createError 函數

完整的代碼,這裏只寫一些改變了的代碼,按照之前的目錄結構,我會在 helpers 中新建立一個 error.ts 文件

import {AxiosRequestConfig,AxiosResponse} from '../types';

export class AxiosError extends Error {
    isAxiosError: boolean
    config: AxiosRequestConfig
    code?: string|null
    request?:any
    response?:AxiosResponse
    constructor(
        message:string,
        config:AxiosRequestConfig,
        code?: string|null,
        request?:any,
        response?: AxiosResponse,

    ){
        super(message);
        this.config = config;
        this.code = code;
        this.request = request;
        this.response = response;
        this.isAxiosError = true;
        Object.setPrototypeOf(this,AxiosError.prototype);
    }
}


export function createError(
    message:string,
    config:AxiosRequestConfig,
    code?: string|null,
    request?:any,
    response?: AxiosResponse,
) {
    return new AxiosError(message,config,code,request,response);
}

types/index.ts 中就添加了一個結構 AxiosError

/...
export interface AxiosError extends Error {
    isAxiosError: boolean,
    config: AxiosRequestConfig,
    code?: string | null,
    request?:any;
    response?:AxiosResponse,
}

還有 xhr.ts 改變過:

import {AxiosRequestConfig,AxiosPromise,AxiosResponse} from './types';
import {parseHeaders} from './helpers/header';
import {createError} from './helpers/error';

export default function xhr(config:AxiosRequestConfig) : AxiosPromise {
    return new Promise((reslove,reject)=> {
        const {data = null,url,method='get',timeout,headers,responseType} = config;
        const request = new XMLHttpRequest();
        
        if(responseType) request.responseType = responseType;

        // 超時操作
        if(timeout) request.timeout = timeout;
    
        request.onreadystatechange = function handleLoad() {
            if(request.readyState !== 4) {
                return;
            }

            if(request.status === 0) {
                // 網絡錯誤和超時錯誤時 status爲 0
                return;
            }

            const responseHeaders = request.getAllResponseHeaders();
            const responseDate = responseType !== 'text' ? request.response : request.responseText;
            const response:AxiosPromise = {
                data:responseDate,
                status:request.status,
                statusText: request.statusText,
                headers: parseHeaders(responseHeaders),
                config,
                request,
            }
            handleResponse(response);
        }

        request.open(method.toUpperCase(),url,true);
// 錯誤開始        
        // 請求錯誤
        request.onerror = function handleError() {
            reject(createError('Network Error',config,null,request));
        } 
        // 超時錯誤
        request.ontimeout = function handleTimeout() {
            reject(createError(`Timeout of ${timeout} ms exceeded`,config,'ECONNABORTED',request));
        }
// 錯誤結束        
        Object.keys(headers).forEach((name) => {
            if(data === null && name.toLocaleLowerCase() === 'content-type') {
                delete headers[name];
            }
            request.setRequestHeader(name,headers[name]);
        })

        request.send(data);

        function handleResponse(response: AxiosResponse) : void{
            if(response.status >= 200 && response.status < 300) {
                reslove(response);
            } else {
                reject(createError(`Request failed with status code ${response.status}`,config,null,request,response));
            }
        }
    })

}

現在就沒有了,就到這裏,之後會就是用這個 axios 方法來擴展一些方法,例如 axios.get 等。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章