Axios 和 Fetch 的用法比较

Axios 和 Fetch 的用法比较。对原生 XMLhttpRequest 的封装。适用于简单的使用。复杂的使用需要再次封装。 ~~~typescript

Axios Fetch 用法比较

Fetch

对原生 XMLhttpRequest 的封装。适用于简单的使用。复杂的使用需要再次封装。

1
2
3
4
5
fetch(url,options).then((response)=>{
//处理http响应
},(error)=>{
//处理错误
})

简单封装

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/**
   * get 请求
   * @param url
   * @param params
   * @param isHandleError
   * @param httpCustomerOpertion 使用者传递过来的参数, 用于以后的扩展用户自定义的行为
   * {
   *    isHandleResult: boolen    //是否需要处理错误结果   true 需要/false 不需要
   *    isShowLoading: boolen     //是否需要显示loading动画
   *    customHead: object        // 自定义的请求头
   *    timeout: int              //自定义接口超时的时间
   * }
   * @returns {Promise}
   */
get(url, params = {}, httpCustomerOpertion = { isHandleResult: true, isShowLoading: true  }) {
    if (!httpCustomerOpertion.hasOwnProperty("isHandleResult")) {
        httpCustomerOpertion.isHandleResult = true
    }
    if (!httpCustomerOpertion.hasOwnProperty("isShowLoading")) {
        httpCustomerOpertion.isShowLoading = true
    }
    const method = "GET"
    const fetchUrl = url + CommonTool.qs(params) // 将参数转化到url上
    const fetchParams = Object.assign({}, { method }, this.getHeaders())
    return HttpUtil.handleFetchData(fetchUrl, fetchParams, httpCustomerOpertion)
}

/**
   * post 请求
   * @param url
   * @param params
   * @param isHandleError
   * @param httpCustomerOpertion 使用者传递过来的参数, 用于以后的扩展用户自定义的行为
   * @returns {Promise}
   */
post(url, params = {}, httpCustomerOpertion = { isHandleResult: true, isShowLoading: true  }) {
    if (!httpCustomerOpertion.hasOwnProperty("isHandleResult")) {
        httpCustomerOpertion.isHandleResult = true
    }
    if (!httpCustomerOpertion.hasOwnProperty("isShowLoading")) {
        httpCustomerOpertion.isShowLoading = true
    }
    const method = "POST"
    const body = JSON.stringify(params) // 将参数转化成JSON字符串
    const fetchParams = Object.assign({}, { method, body }, this.getHeaders())
    return HttpUtil.handleFetchData(url, fetchParams, httpCustomerOpertion)
}


/**  * 发送fetch请求
   * @param fetchUrl
   * @param fetchParams
   * @returns {Promise}
   */
static handleFetchData(fetchUrl, fetchParams, httpCustomerOpertion) {   // 1. 处理的第一步
    const { isShowLoading } = httpCustomerOpertion
    if (isShowLoading) {
        HttpUtil.showLoading()
    }
    httpCustomerOpertion.isFetched = false
    httpCustomerOpertion.isAbort = false
    // 处理自定义的请求头
    if (httpCustomerOpertion.hasOwnProperty("customHead")) {
        const { customHead } = httpCustomerOpertion
        fetchParams.headers = Object.assign({}, fetchParams.headers, customHead)
    }   // 2. 对fetch请求再进行一次Promise的封装
    const fetchPromise = new Promise((resolve, reject) => {
        fetch(fetchUrl, fetchParams).then(
            response => {      // 3. 放弃迟到的响应
                if (httpCustomerOpertion.isAbort) {
                    // 3. 请求超时后,放弃迟到的响应
                    return
                }
                if (isShowLoading) {
                    HttpUtil.hideLoading()
                }
                httpCustomerOpertion.isFetched = true
                response.json().then(jsonBody => {
                    if (response.ok) {         // 4. 统一处理返回结果
                        if (jsonBody.status === 5) {
                            // token失效,重新登录
                            CommonTool.turnToLogin()
                        } else if (jsonBody.status) {
                            // 业务逻辑报错, 不属于接口报错的范畴
                            reject(HttpUtil.handleFailedResult(jsonBody, httpCustomerOpertion))
                        } else {
                            resolve(HttpUtil.handleResult(jsonBody, httpCustomerOpertion))
                        }
                    } else {         // 5. 接口状态判断
                        // http status header <200 || >299
                        let msg = "当前服务繁忙,请稍后再试"
                        if (response.status === 404) {
                            msg = "您访问的内容走丢了…"
                        }        
                        Toast.info(msg, 2)
                        reject(HttpUtil.handleFailedResult({ fetchStatus: "error", netStatus: response.status, error: msg }, httpCustomerOpertion))
                    }
                }).catch(e => {
                    const errMsg = e.name + " " + e.message
                    reject(HttpUtil.handleFailedResult({ fetchStatus: "error", error: errMsg, netStatus: response.status }, httpCustomerOpertion))
                })
            }
        ).catch(e => {
            const errMsg = e.name + " " + e.message
            // console.error('ERR:', fetchUrl, errMsg)
            if (httpCustomerOpertion.isAbort) {
                // 请求超时后,放弃迟到的响应
                return
            }
            if (isShowLoading) {
                HttpUtil.hideLoading()
            }
            httpCustomerOpertion.isFetched = true
            httpCustomerOpertion.isHandleResult && Toast.info("网络开小差了,稍后再试吧", 2)
            reject(HttpUtil.handleFailedResult({ fetchStatus: "error", error: errMsg }, httpCustomerOpertion))
        })
    })
    return Promise.race([fetchPromise, HttpUtil.fetchTimeout(httpCustomerOpertion)])
}


/**
   * 统一处理后台返回的结果, 包括业务逻辑报错的结果
   * @param result
   * ps: 通过 this.isHandleError 来判断是否需要有fetch方法来统一处理错误信息
   */
static handleResult(result, httpCustomerOpertion) {
    if (result.status && httpCustomerOpertion.isHandleResult === true) {
        const errMsg = result.msg || result.message || "服务器开小差了,稍后再试吧"
        const errStr = `${errMsg}${result.status})`
        HttpUtil.hideLoading()
        Toast.info(errStr, 2)
    }
    return result
}
/**
   * 统一处fetch的异常, 不包括业务逻辑报错
   * @param result
   * ps: 通过 this.isHandleError 来判断是否需要有fetch方法来统一处理错误信息
   */
static handleFailedResult(result, httpCustomerOpertion) {
    if (result.status && httpCustomerOpertion.isHandleResult === true) {
        const errMsg = result.msg || result.message || "服务器开小差了,稍后再试吧"
        const errStr = `${errMsg}${result.status})`
        HttpUtil.hideLoading()
        Toast.info(errStr, 2)
    }
    const errorMsg = "Uncaught PromiseError: " + (result.netStatus || "") + " " + (result.error || result.msg || result.message || "")
    return errorMsg
}
/**
   * 控制Fetch请求是否超时
   * @returns {Promise}
   */
static fetchTimeout(httpCustomerOpertion) {
    const { isShowLoading } = httpCustomerOpertion
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            if (!httpCustomerOpertion.isFetched) {
                // 还未收到响应,则开始超时逻辑,并标记fetch需要放弃
                httpCustomerOpertion.isAbort = true
                // console.error('ERR: 请求超时')
                if (isShowLoading) {
                    HttpUtil.hideLoading()
                }
                Toast.info("网络开小差了,稍后再试吧", 2)
                reject({ fetchStatus: "timeout" })
            }
        }, httpCustomerOpertion.timeout || timeout)
    })
}

Axios

对原生 XMLhttpRequest 的封装。

基础使用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
// axios.get(url[, config])
// get
axios.get('apiURL', {
    param: {
        id: 1
    }
    // param 中的的键值对最终会 ? 的形式,拼接到请求的链接上,发送到服务器。
}).then(res => {
    console.log(res)
}).catch( error => {
    console.log(error)
})

// post
axios.post('apiURL',{
    user: '小新',
    age: 18
}).then( res => {
    console.log(res);
}).catch( error => {
    console.log(error)
});

拦截器

拦截器常用于用户认证、接口报错拦截处理、整体日志处理等

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// 请求拦截器
axios.interceptors.request.use(config => {
  console.log(`请求拦截`);
  return config;
});

// 响应拦截器 
axios.interceptors.response.use(response => {
  // 对响应数据做点什么 
  console.log(`成功的响应拦截`);
  return response.data;
});
Gear(夕照)的博客。记录开发、生活,以及一些不足为道的思考……