安装依赖

npx create-react-app zaxios —typescript 使用react脚手架实现工程
cd .\zaxios\
yarn add axios @types/axios qs @types/qs parse-headers (前台请求)
yarn add express body-parser (写后台服务和接口)
yarn start (启动服务 ,可以删除一些没用的代码)

先准备后台环境

在根目录下,准备node环境,并启动服务,准备几个简单的接口
node api

  1. let express = require("express");
  2. let bodyParser = require('body-parser');
  3. let app = express();
  4. app.use(bodyParser.json());
  5. app.use(bodyParser.urlencoded({ extended: true }));
  6. app.use(function (req, res, next) {
  7. res.set({
  8. 'Access-Control-Allow-Origin': 'http://localhost:3000',
  9. 'Access-Control-Allow-Credentials': true,
  10. 'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS',
  11. 'Access-Control-Allow-Headers': 'Content-Type,name'
  12. });
  13. if (req.method === 'OPTIONS') {
  14. return res.sendStatus(200)
  15. };
  16. next()
  17. })
  18. app.get('/get', function (req, res) {
  19. res.json(req.query)
  20. })
  21. app.post('/post', function (req, res) {
  22. res.json(req.body)
  23. })
  24. app.post('/post_timeout', function (req, res) {
  25. let { timeout } = req.query;
  26. console.log(req.query);
  27. if (timeout) {
  28. timeout = parseInt(timeout);
  29. } else {
  30. timeout = 0;
  31. }
  32. setTimeout(() => {
  33. res.json(req.body)
  34. }, timeout);
  35. })
  36. app.post('/post_status', function (req, res) {
  37. let { code } = req.query;
  38. if (code) {
  39. code = parseInt(code);
  40. } else {
  41. code = 200;
  42. }
  43. res.statusCode = code;
  44. res.json(req.body)
  45. })
  46. app.listen(8080);

Record

Record < string,any>的意思如下 :
export interface PlainObject {
[name: string]: any
}

axios边界错误

1.错误网络异常错误

当网络出现异常(比如网络不通)的时候,发送请求会触发XMLHTTPRequest对象实例的error事件。于是,我们可以在onerror的事件回调函数中捕获此类错误。

2. 处理超时错误

我们可以设置某个请求的超时时间timeout,也就是当请求发送后超过某个时间仍然没有收到相应,则请求自动终止,并触发timeout事件。
请求默认的超时时间是0,即永不超时,所以我们首先需要允许程序可以配置超时时间

3. 状态码错误

对于状态码不在200-300之间的,进行错误反馈

src同级 新建typings /parse-header.d.ts

  1. //如果说你导入了一个模块是js 的,但是没有官方的类型声明文件
  2. //也没有第三方的 ,自己也不想写
  3. //就可以直接 declare module 声明一个模块;
  4. declare module 'parse-headers';

src/

axios文件夹

types.tsx定义一些类型

  1. //type 定义 ,方法的各种类型, 类型为任取其中一个
  2. export type Methods = 'get' | 'post' | 'put' | 'delete' | 'GET' | 'POST' | 'PUT' | 'DELECT' | 'OPTIONS' | 'options';
  3. //Axios.prototype.request这个方法
  4. //Promise 的泛型T代表此 proimse变成成功状态之后的,resovle的值 resovle(Value)
  5. export interface AxiosInstance {
  6. //接收泛型 参数类型为请求类型 返回一个包括promise的泛型
  7. <T = any>(config: AxiosRequestConfig): Promise<T>
  8. }
  9. //定义请求参数
  10. export interface AxiosRequestConfig {
  11. url?: string,
  12. method?: Methods,
  13. params?: any,
  14. headers?: Record<string, any>,
  15. data?: Record<string, any>,
  16. timeout?: number
  17. }
  18. //定义返回参数
  19. export interface AxiosResponse<T = any> {
  20. data: T;
  21. status: number;
  22. statusText: string;
  23. headers?: Record<string, any>;
  24. config?: AxiosRequestConfig;
  25. request?: XMLHttpRequest;
  26. }

Axios.tsx定义axios主要方法

  1. import { AxiosRequestConfig, AxiosResponse } from "./types";
  2. import qs from "qs";
  3. import parseHeaders from 'parse-headers';
  4. export default class Axios {
  5. //T用来限制相应对象response里的data的类型
  6. //request方法,在init的时候会绑定
  7. request<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
  8. return this.dispatchRequest(config);
  9. }
  10. //定义一个派发请求的方法
  11. dispatchRequest<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {
  12. //返回一个 promise ,接收一个函数作为参数,
  13. return new Promise<AxiosResponse<T>>(function (resolve, reject) {
  14. //从参数解构出数据,进行组合
  15. let { method, url, params, headers, data, timeout } = config;
  16. //新建一个请求
  17. let request = new XMLHttpRequest();
  18. //如果有请求头,就设置请求头
  19. if (headers) {
  20. for (let key in headers) {
  21. request.setRequestHeader(key, headers[key]);
  22. }
  23. }
  24. //如果有get请求的params
  25. if (params) {
  26. //转变成字符串
  27. params = qs.stringify(params);
  28. //判断url有没有?如果有就返回&如果没有就返回?
  29. url += ((url!.indexOf("?") !== -1 ? "&" : "?") + params);
  30. }
  31. //body进行处理
  32. let body: string | null = null;
  33. if (data) {
  34. body = JSON.stringify(data);
  35. }
  36. request.send(body);
  37. //启动请求 这里的因为加了参数? 所以在使用的时候就需要断言
  38. request.open(method!, url!, true);
  39. //请求合适为json
  40. request.responseType = 'json';
  41. //状态改变的回调函数
  42. request.onreadystatechange = function () { //指定一个状态变更函数
  43. //readyState 0 1 2 3 4 4表示完成
  44. //status 表示状态码
  45. if (request.readyState === 4 && request.status !== 0) {
  46. //如果是200 到300 之间都认为是成功,返回res
  47. if (request.status >= 200 && request.status < 300) {
  48. let response: AxiosResponse<T> = {
  49. //返回结果
  50. data: request.response ? request.response : request.responseText,
  51. status: request.status,
  52. statusText: request.statusText,
  53. //这里是 用第三方包,把请求头全部接收到然后转换下格式
  54. headers: parseHeaders(request.getAllResponseHeaders()),
  55. config,
  56. request
  57. }
  58. //改变 承诺状态
  59. resolve(response);
  60. } else {
  61. //返回失败状态
  62. //这里是 兼容了问题3. 状态码错误
  63. reject(`Error: Request failed with status code ${request.status}`)
  64. }
  65. }
  66. }
  67. //实现延时报错 问题1.错误网络异常错误
  68. request.onerror = function () {
  69. // 改变proimse状态 报错
  70. reject('net::ERR_INTERNET_DISCONNECTED');
  71. }
  72. //实现超时事件 问题2.处理超时错误
  73. if (timeout) {
  74. //需要让request对象知道设置的请求时间
  75. request.timeout = timeout;
  76. //当超时的回调
  77. request.ontimeout = function () {
  78. reject(`Error timeout of ${timeout}ms exceeded`)
  79. }
  80. }
  81. })
  82. }
  83. }

index.tsx

  1. import Axios from "./Axios";
  2. import { AxiosInstance } from "./types";
  3. //可以创建一个axios实例 axios其实是一个函数
  4. //定义一个类的时候,一个是类的原型,Axios.prototype ,一个是类得到实例
  5. function createInstance(): AxiosInstance {
  6. let context: Axios = new Axios();//this指针上下文
  7. //让request 方法里的this永远指向 context
  8. let instance = Axios.prototype.request.bind(context);
  9. //把Axios的类的实例和原型 上的方法,都拷贝到了instance,也就是request上
  10. instance = Object.assign(instance, Axios.prototype, context);
  11. return instance as AxiosInstance;
  12. }
  13. let axios = createInstance();
  14. //暴露axios
  15. export default axios;
  16. //暴露所有写好的类
  17. export * from './types'

src/index.tsx(使用)

  1. import axios, { AxiosResponse } from "./axios";
  2. const baseUrl = 'http://localhost:8080';
  3. //它值得是服务器返回的对象
  4. interface User {
  5. name: string;
  6. password: string
  7. }
  8. let user: User = {
  9. name: 'qwe',
  10. password: '123456'
  11. }
  12. setTimeout(function () {
  13. axios({
  14. method: "post", //方法名
  15. url: baseUrl + "/post", //访问路径
  16. // url: baseUrl + "/post", //访问路径
  17. headers: {
  18. 'content-type': 'application/json'
  19. },
  20. timeout: 1000,
  21. data: user //查询参数 ,会转成查询字符串放在?号的后面
  22. // method: "get", //方法名
  23. // url: baseUrl + "/get", //访问路径
  24. // params: user //查询参数 ,会转成查询字符串放在?号的后面
  25. }).then((res: AxiosResponse<User>) => {
  26. console.log(res);
  27. return res.data;
  28. }).catch((error: any) => {
  29. console.log(error)
  30. })
  31. }, 5000)