当前位置 : 首页 > 保养数据

《Axios响应处理:构建完整响应对象与异常处理》

<|begin▁of▁sentence|># 1. 前言 在上一篇文章中,我们实现了处理响应`headers`、并解析获得`headers`对象。接下来,我们就在获取到`headers`对象的基础上,继续实现对响应`data`的处理。 根据上一篇文章中,我们设计的`axios`接口,我们希望`axios`函数能够返回一个`promise`对象,并且能够接收到一个响应对象`response`,其中该响应对象包括:`data`、`status`、`statusText`、`headers`、`config`、`request`。如下: ```typescript axios({ method: "get", url: "/api/handleResponse", }).then((res) => { console.log(res); }); ``` 我们希望`then`函数中得到的`res`对象是这样的: ```json { "data": { "text": "hello world" }, "status": 200, "statusText": "OK", "headers": { "content-type": "application/json; charset=utf-8", "date": "Sat, 21 Sep 2019 13:55:54 GMT", "connection": "close", "content-length": "17" }, "config": { // ... }, "request": { // ... } } ``` # 2. 需求分析 从需求分析中,我们可以看出,我们需要在`then`函数中拿到一个`response`对象,该对象中不仅包含`data`、`status`、`statusText`、`headers`,还包含我们之前传给`axios`函数的配置对象`config`和我们发送请求的`XMLHttpRequest`对象实例`request`。 所以,我们首先要创建一个`response`对象,该对象包含上面这些属性,然后我们在`onreadystatechange`事件函数中,当`readyState`为`4`的时候,也就是接收到响应的时候,将`response`对象传给`resolve`函数即可。 # 3. 创建响应对象 根据需求,我们创建`src/types/index.ts`文件,并在其中定义`AxiosResponse`接口类型,该类型接口包含`data`、`status`、`statusText`、`headers`、`config`和`request`属性。 ```typescript export interface AxiosResponse { data: any; // 服务端返回的数据 status: number; // HTTP 状态码 statusText: string; // 状态消息 headers: any; // 响应头 config: AxiosRequestConfig; // 请求配置对象 request: any; // 请求的 XMLHttpRequest 对象实例 } ``` 另外,我们`axios`函数返回的是`Promise`对象,我们可以定义一个`AxiosPromise`接口,它继承于`Promise`泛型接口: ```typescript export interface AxiosPromise extends Promise {} ``` 这样的话,当`axios`返回的是`AxiosPromise`类型时,`resolve`函数中的参数就是一个`AxiosResponse`类型。 # 4. 实现逻辑 首先,我们在`src/xhr.ts`中,在`onreadystatechange`事件函数中,如果`readyState`不为 4,则直接返回。 ```typescript if (xhr.readyState !== 4) { return; } ``` 然后,我们获取到响应`headers`,这个在上一篇文章中已经实现,然后我们再获取到响应`data`、`status`、`statusText`,接着把它们构建成一个`response`对象,然后传给`resolve`函数。 ```typescript const responseHeaders = parseHeaders(xhr.getAllResponseHeaders()); const responseData = xhr.responseText; const response: AxiosResponse = { data: responseData, status: xhr.status, statusText: xhr.statusText, headers: responseHeaders, config, request: xhr, }; resolve(response); ``` 另外,我们虽然发送了请求,并且也接收到了响应,但是有可能网络异常或者请求超时,这个时候我们应该在`onerror`事件函数和`ontimeout`事件函数中,使用`reject`函数,把错误信息返回。 ```typescript // 处理错误 xhr.onerror = function() { reject(new Error("Network Error")); }; // 处理超时 xhr.ontimeout = function() { reject(new Error(`Timeout of ${config.timeout} ms exceeded`)); }; ``` OK,这样我们就实现了对响应`data`的处理,并且还处理了网络异常和请求超时的情况。 # 5. 编写 demo 在 `examples` 目录下创建 `handleResponse`目录,在 `handleResponse`目录下创建 `index.`: ``` < lang="en"> Handle response example ``` 接着再创建 `app.ts` 作为入口文件: ```typescript import axios from "../../src/index"; axios({ method: "get", url: "/api/handleResponse", }) .then((res) => { console.log(res); }) .catch((e) => { console.log(e); }); axios({ method: "get", url: "/api/handleResponse1", }) .then((res) => { console.log(res); }) .catch((e) => { console.log(e); }); axios({ method: "get", url: "/api/handleResponse2", }) .then((res) => { console.log(res); }) .catch((e) => { console.log(e); }); setTimeout(() => { axios({ method: "get", url: "/api/handleResponse", timeout: 2000, }) .then((res) => { console.log(res); }) .catch((e) => { console.log(e); }); }, 5000); ``` 接着在 `server.js` 中添加新的接口路由: ```javascript // 响应正常 router.get("/api/handleResponse", function(req, res) { res.json({ text: "hello world", }); }); // 响应异常 router.get("/api/handleResponse1", function(req, res) { res.status(500).send("server error"); }); // 响应超时 router.get("/api/handleResponse2", function(req, res) { setTimeout(() => { res.json({ text: "hello world", }); }, 3000); }); ``` 最后在根目录下的`index.`中加上启动该`demo`的入口: ```
  • Handle response
  • ``` # 6. 运行 demo 接着我们在命令行中执行: ```bash # 同时开启客户端和服务端 npm run server | npm start ``` 接着我们打开 `chrome` 浏览器,访问 即可访问我们的 `demo` 了,我们点击 `Handle response`,通过`F12`的 `network` 部分我们可以看到发送的请求,并且`console`中输出: - 正常响应 ![](~@/axios/05/01.png) - 异常响应 ![](~@/axios/05/02.png) - 超时响应 ![](~@/axios/05/03.png) - 超时设置 ![](~@/axios/05/04.png) OK,这样我们就实现了对响应`data`的处理。

    栏目列表