0. 系列文章

1.使用Typescript重构axios(一)——写在最前面

2.使用Typescript重构axios(二)——项目起手,跑通流程

3.使用Typescript重构axios(三)——实现基础功能:处理get请求url参数

4.使用Typescript重构axios(四)——实现基础功能:处理post请求参数

5.使用Typescript重构axios(五)——实现基础功能:处理请求的header

6.使用Typescript重构axios(六)——实现基础功能:获取响应数据

7.使用Typescript重构axios(七)——实现基础功能:处理响应header

8.使用Typescript重构axios(八)——实现基础功能:处理响应data

9.使用Typescript重构axios(九)——异常处理:基础版

10.使用Typescript重构axios(十)——异常处理:增强版

11.使用Typescript重构axios(十一)——接口扩展

12.使用Typescript重构axios(十二)——增加参数

13.使用Typescript重构axios(十三)——让响应数据支持泛型

14.使用Typescript重构axios(十四)——实现拦截器

15.使用Typescript重构axios(十五)——默认配置

16.使用Typescript重构axios(十六)——请求和响应数据配置化

17.使用Typescript重构axios(十七)——增加axios.create

18.使用Typescript重构axios(十八)——请求取消功能:总体思路

19.使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式

20.使用Typescript重构axios(二十)——请求取消功能:实现第一种使用方式

21.使用Typescript重构axios(二十一)——请求取消功能:添加axios.isCancel接口

22.使用Typescript重构axios(二十二)——请求取消功能:收尾

23.使用Typescript重构axios(二十三)——添加withCredentials属性

24.使用Typescript重构axios(二十四)——防御XSRF攻击

25.使用Typescript重构axios(二十五)——文件上传下载进度监控

26.使用Typescript重构axios(二十六)——添加HTTP授权auth属性

27.使用Typescript重构axios(二十七)——添加请求状态码合法性校验

28.使用Typescript重构axios(二十八)——自定义序列化请求参数

29.使用Typescript重构axios(二十九)——添加baseURL

30.使用Typescript重构axios(三十)——添加axios.getUri方法

31.使用Typescript重构axios(三十一)——添加axios.all和axios.spread方法

32.使用Typescript重构axios(三十二)——写在最后面(总结)

项目源码请猛戳这里!!!

1. 前言

在之前的文章中,不管是get请求还是post请求都已经可以正常发出了,并且在浏览器的F12中也都能正确的看到返回的数据了,但这仅仅是在浏览器中利用开发者工具看到返回的数据,而在代码中我们还是无法拿到返回的数据,我们期望的使用方式应该是如下样子的:

axios({
method: 'post',
url: '/api/getResponse',
data: {
a: 1,
b: 2
}
}).then((res) => {
console.log(res)
})

我们期望能够拿到服务端响应的数据,并且支持 Promise 链式调用的方式。

2. 响应数据接口定义

我们先来分析下,我们都想要拿到服务端给我们响应哪些数据:首先最主要的服务端返回的数据data不能少,其次,例如HTTP 状态码status,状态消息 statusText,响应头 headers、请求配置对象 config 以及请求的 XMLHttpRequest 对象实例 request,这些信息我们也都想拿到,基于此,我们先在src/types/index.ts中定义一下服务端响应的数据接口类型AxiosResponse,如下:

export interface AxiosResponse {
data: any; // 服务端返回的数据
status: number; // HTTP 状态码
statusText: string; // 状态消息
headers: any; // 响应头
config: AxiosRequestConfig; // 请求配置对象
request: any; // 请求的 XMLHttpRequest 对象实例
}

另外,我们还期望axios 函数能够返回一个 Promise 对象,以满足我们想要的链式调用,那么我们可以定义一个 AxiosPromise 接口,它继承于 Promise<AxiosResponse> 这个泛型接口:

export interface AxiosPromise extends Promise<AxiosResponse> {
}

这样的话,当 axios 返回的是 AxiosPromise 类型,那么 resolve 函数中的参数就是一个 AxiosResponse 类型。

对于一个 AJAX 请求的响应,我们在发送请求的时候还可以通过设置 XMLHttpRequest对象的responseType属性来指定它响应数据的类型responseType (responseType的MDN介绍),于是,我们可以给之前定义好的 AxiosRequestConfig 类型添加一个可选属性responseType,添加后如下:

export interface AxiosRequestConfig {
url: string;
method?: Method;
headers?: any;
data?: any;
params?: any;
responseType?: XMLHttpRequestResponseType;
}

responseType 的类型是一个 XMLHttpRequestResponseType 类型,它的定义是 "" | "arraybuffer" | "blob" | "document" | "json" | "text" 字符串字面量类型。

3. 获取响应

定义好响应数据的接口类型后,我们就可以来写获取响应的逻辑了。我们知道,一个完整的AJAX流程大致分为4步:

  1. 创建XMLHttpRequest异步对象;

  2. 配置请求参数;

  3. 发送请求;

  4. 注册事件,获取响应数据

之前在src/xhr.ts中我们已经完成了前3步,那么接下来我们就实现第4步:

import { AxiosPromise, AxiosRequestConfig, AxiosResponse } from "./types";

export default function xhr(config: AxiosRequestConfig): AxiosPromise {
return new Promise((resolve, reject) => {
const { data = null, url, method = "get", headers, responseType } = config; // 1.创建XMLHttpRequest异步对象
const request = new XMLHttpRequest();
// 2.配置请求参数
request.open(method.toUpperCase(), url, true); Object.keys(headers).forEach(name => {
if (data === null && name.toLowerCase() === "content-type") {
delete headers[name];
}
request.setRequestHeader(name, headers[name]);
}); if (responseType) {
request.responseType = responseType;
} // 3.发送请求
request.send(data);
// 4.注册事件,拿到响应信息
request.onreadystatechange = function handleLoad() {
if (request.readyState !== 4) {
return;
}
const responseHeaders = request.getAllResponseHeaders();
const responseData =
responseType && responseType !== "text"
? request.response
: request.responseText;
const response: AxiosResponse = {
data: responseData,
status: request.status,
statusText: request.statusText,
headers: responseHeaders,
config,
request
};
resolve(response);
};
});
}

这里,我们还判断了如果 config 中配置了 responseType,我们要把它设置到 request.responseType 中。

另外,当 responseType没有设置或者设置为text时,响应数据存在于request.responseText,其余情况,响应数据存在于request.response,所以我们添加了这行代码:

const responseData = responseType && responseType !== "text"? request.response: request.responseText;

最后,在 onreadystatechange 事件函数中,我们构造了 AxiosResponse 类型的 reponse 对象,并把它 resolve 出去。

修改了 xhr 函数,我们同样也要对应修改 axios 函数:

// src/index.ts

function axios(config: AxiosRequestConfig): AxiosPromise {
processConfig(config)
return xhr(config)
}

OK,获取响应就已经完成了,接下来,我们就可以编写demo来测试下效果怎么样。

4. 编写demo

examples 目录下创建 getResponse目录,在 getResponse目录下创建 index.html:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>getResponse demo</title>
</head>
<body>
<script src="/__build__/getResponse.js"></script>
</body>
</html>

接着再创建 app.ts 作为入口文件:

import axios from "../../src/index";

axios({
method: "post",
url: "/api/getResponse",
data: {
a: 1,
b: 2
}
}).then(res => {
console.log(res);
}); axios({
method: "post",
url: "/api/getResponse",
responseType: "json",
data: {
a: 3,
b: 4
}
}).then(res => {
console.log(res);
});

接着在 server/server.js 添加新的接口路由:

router.post("/api/getResponse", function(req, res) {
res.json(req.body);
});

最后在根目录下的index.html中加上启动该demo的入口:

<li><a href="examples/getResponse">getResponse</a></li>

OK,我们在命令行中执行:

# 同时开启客户端和服务端
npm run server | npm start

接着我们打开 chrome 浏览器,访问 http://localhost:8000/ 即可访问我们的 demo 了,我们点击 getResponse,通过F12的控制台我们可以看到:两条请求的响应信息都已经被打印出来了,并且第一条请求我们没有指定responseType属性,它默认为text,打印出来的data数据就是字符串类型,而第二条请求我们指定了responseType: "json",打印出来的data数据就是json类型的。

5. 遗留问题

从上图中我们还看到,打印出来的headers变成了字符串类型,并不是我们之前设置的对象类型,而且如果返回的data是一个json字符串,我们还应该给它转换成对象类型的。那么后面我们就来做这两件事情。

(完)

使用Typescript重构axios(六)——实现基础功能:获取响应数据的更多相关文章

  1. 使用Typescript重构axios(三)——实现基础功能:处理get请求url参数

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  2. 使用Typescript重构axios(四)——实现基础功能:处理post请求参数

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  3. 使用Typescript重构axios(五)——实现基础功能:处理请求的header

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  4. 使用Typescript重构axios(七)——实现基础功能:处理响应header

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  5. 使用Typescript重构axios(八)——实现基础功能:处理响应data

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  6. 使用Typescript重构axios(九)——异常处理:基础版

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  7. 使用Typescript重构axios(十六)——请求和响应数据配置化

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  8. 使用Typescript重构axios(十八)——请求取消功能:总体思路

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

  9. 使用Typescript重构axios(十九)——请求取消功能:实现第二种使用方式

    0. 系列文章 1.使用Typescript重构axios(一)--写在最前面 2.使用Typescript重构axios(二)--项目起手,跑通流程 3.使用Typescript重构axios(三) ...

随机推荐

  1. Android通过外部浏览器调用微信H5支付,Android+PHP详解

    看了好多关于讲解微信H5支付开发的文章,大多数都是通过微信内部浏览器来调用支付接口(其实就是公众号支付),可能是因为H5支付接口刚开放不久吧. 微信官方体验链接:http://wxpay.wxutil ...

  2. MySql权限丢失问题解决

    参考文章 [mysql] root权限丢失恢复 完全菜鸟教程 今天用root账户登录到mysql后, show databases 命令返回的只有两个表, 然后使用 use database 命令提示 ...

  3. VGG(2014),3x3卷积的胜利

    目录 写在前面 网络结构 multi-scale training and testing 其他有意思的点 参考 博客:blog.shinelee.me | 博客园 | CSDN 写在前面 VGG(2 ...

  4. linux netlink通信机制简介

    一.什么是Netlink通信机制  Netlink套接字是用以实现用户进程与内核进程通信的一种特殊的进程间通信(IPC) ,也是网络应用程序与内核通信的最常用的接口. Netlink 是一种特殊的 s ...

  5. .Net TCP探索(一)——TCP服务端开发(同时监听多个客户端请求)

        最近在园子里看了大神写的(面试官,不要再问我三次握手和四次挥手),忍不住写段程序来测试一番.     在网上找了很多例子,大多只实现了TCP点对点通讯,但实际应用中,一个服务器端口往往要监听多 ...

  6. sql server中Set与select的区别

    Set与select的区别 Set select 同时多个变量赋值 不支持 支持 表达式返回多个值时 出错 将返回的最后一个值赋给变量 表达式未返回值 变量被null赋值 变量保持原始值

  7. eclipse常用快捷键即项目操作

    快捷键: 1.代码提示:Alt+/ 2.撤销上一步操作:Ctrl+z:取消撤销:Ctrl+y: 3.如何注销一整段代码?☞▲第一种注释方法是每行代码前加//:先选中,然后按Ctrl+/:取消注销方法一 ...

  8. Ubuntu 安装中文

    系统环境:

  9. PMP(第六版)中的控制账户、规划包、工作包

    PMP(第六版)中的控制账户.规划包.工作包 控制账户是一个管理控制点,在该控制点上,把范围.预算和进度加以整合,并与挣值比较,以测量绩效.控制账户拥有2个或以上的工作包,但每个工作包只与一个控制账户 ...

  10. 抛弃Eclipse,投入IDEA 的独孤求败江湖

    "工欲善其事,必先利其器" 出处:孔子<论语> 两年了,这是我的 IDEA 实用技巧总结,从前我是一个 Eclipse 忠实用户,直到某天我用上了 IntelliJ I ...