安装依赖
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
let express = require("express");let bodyParser = require('body-parser');let app = express();app.use(bodyParser.json());app.use(bodyParser.urlencoded({ extended: true }));app.use(function (req, res, next) {res.set({'Access-Control-Allow-Origin': 'http://localhost:3000','Access-Control-Allow-Credentials': true,'Access-Control-Allow-Methods': 'GET,POST,PUT,DELETE,OPTIONS','Access-Control-Allow-Headers': 'Content-Type,name'});if (req.method === 'OPTIONS') {return res.sendStatus(200)};next()})app.get('/get', function (req, res) {res.json(req.query)})app.post('/post', function (req, res) {res.json(req.body)})app.post('/post_timeout', function (req, res) {let { timeout } = req.query;console.log(req.query);if (timeout) {timeout = parseInt(timeout);} else {timeout = 0;}setTimeout(() => {res.json(req.body)}, timeout);})app.post('/post_status', function (req, res) {let { code } = req.query;if (code) {code = parseInt(code);} else {code = 200;}res.statusCode = code;res.json(req.body)})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
//如果说你导入了一个模块是js 的,但是没有官方的类型声明文件//也没有第三方的 ,自己也不想写//就可以直接 declare module 声明一个模块;declare module 'parse-headers';
src/
axios文件夹
types.tsx定义一些类型
//type 定义 ,方法的各种类型, 类型为任取其中一个export type Methods = 'get' | 'post' | 'put' | 'delete' | 'GET' | 'POST' | 'PUT' | 'DELECT' | 'OPTIONS' | 'options';//Axios.prototype.request这个方法//Promise 的泛型T代表此 proimse变成成功状态之后的,resovle的值 resovle(Value)export interface AxiosInstance {//接收泛型 参数类型为请求类型 返回一个包括promise的泛型<T = any>(config: AxiosRequestConfig): Promise<T>}//定义请求参数export interface AxiosRequestConfig {url?: string,method?: Methods,params?: any,headers?: Record<string, any>,data?: Record<string, any>,timeout?: number}//定义返回参数export interface AxiosResponse<T = any> {data: T;status: number;statusText: string;headers?: Record<string, any>;config?: AxiosRequestConfig;request?: XMLHttpRequest;}
Axios.tsx定义axios主要方法
import { AxiosRequestConfig, AxiosResponse } from "./types";import qs from "qs";import parseHeaders from 'parse-headers';export default class Axios {//T用来限制相应对象response里的data的类型//request方法,在init的时候会绑定request<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {return this.dispatchRequest(config);}//定义一个派发请求的方法dispatchRequest<T>(config: AxiosRequestConfig): Promise<AxiosResponse<T>> {//返回一个 promise ,接收一个函数作为参数,return new Promise<AxiosResponse<T>>(function (resolve, reject) {//从参数解构出数据,进行组合let { method, url, params, headers, data, timeout } = config;//新建一个请求let request = new XMLHttpRequest();//如果有请求头,就设置请求头if (headers) {for (let key in headers) {request.setRequestHeader(key, headers[key]);}}//如果有get请求的paramsif (params) {//转变成字符串params = qs.stringify(params);//判断url有没有?如果有就返回&如果没有就返回?url += ((url!.indexOf("?") !== -1 ? "&" : "?") + params);}//body进行处理let body: string | null = null;if (data) {body = JSON.stringify(data);}request.send(body);//启动请求 这里的因为加了参数? 所以在使用的时候就需要断言request.open(method!, url!, true);//请求合适为jsonrequest.responseType = 'json';//状态改变的回调函数request.onreadystatechange = function () { //指定一个状态变更函数//readyState 0 1 2 3 4 4表示完成//status 表示状态码if (request.readyState === 4 && request.status !== 0) {//如果是200 到300 之间都认为是成功,返回resif (request.status >= 200 && request.status < 300) {let response: AxiosResponse<T> = {//返回结果data: request.response ? request.response : request.responseText,status: request.status,statusText: request.statusText,//这里是 用第三方包,把请求头全部接收到然后转换下格式headers: parseHeaders(request.getAllResponseHeaders()),config,request}//改变 承诺状态resolve(response);} else {//返回失败状态//这里是 兼容了问题3. 状态码错误reject(`Error: Request failed with status code ${request.status}`)}}}//实现延时报错 问题1.错误网络异常错误request.onerror = function () {// 改变proimse状态 报错reject('net::ERR_INTERNET_DISCONNECTED');}//实现超时事件 问题2.处理超时错误if (timeout) {//需要让request对象知道设置的请求时间request.timeout = timeout;//当超时的回调request.ontimeout = function () {reject(`Error timeout of ${timeout}ms exceeded`)}}})}}
index.tsx
import Axios from "./Axios";import { AxiosInstance } from "./types";//可以创建一个axios实例 axios其实是一个函数//定义一个类的时候,一个是类的原型,Axios.prototype ,一个是类得到实例function createInstance(): AxiosInstance {let context: Axios = new Axios();//this指针上下文//让request 方法里的this永远指向 contextlet instance = Axios.prototype.request.bind(context);//把Axios的类的实例和原型 上的方法,都拷贝到了instance,也就是request上instance = Object.assign(instance, Axios.prototype, context);return instance as AxiosInstance;}let axios = createInstance();//暴露axiosexport default axios;//暴露所有写好的类export * from './types'
src/index.tsx(使用)
import axios, { AxiosResponse } from "./axios";const baseUrl = 'http://localhost:8080';//它值得是服务器返回的对象interface User {name: string;password: string}let user: User = {name: 'qwe',password: '123456'}setTimeout(function () {axios({method: "post", //方法名url: baseUrl + "/post", //访问路径// url: baseUrl + "/post", //访问路径headers: {'content-type': 'application/json'},timeout: 1000,data: user //查询参数 ,会转成查询字符串放在?号的后面// method: "get", //方法名// url: baseUrl + "/get", //访问路径// params: user //查询参数 ,会转成查询字符串放在?号的后面}).then((res: AxiosResponse<User>) => {console.log(res);return res.data;}).catch((error: any) => {console.log(error)})}, 5000)
