赞
踩
现在我们的项目需要升级,技术栈为Vue3
+TypeScript
。所以,现在我需要使用TS对axios进行重新封装
使用npm安装axios依赖
npm install axios
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios'; class Request { private instance: AxiosInstance | undefined constructor(config: AxiosRequestConfig) { this.instance = axios.create(config) } request(config: AxiosRequestConfig): Promise<AxiosResponse> { return new Promise<AxiosResponse>((resolve, reject) => { this.instance?.request(config) .then((res) => { resolve(res) }) .catch((err) => { reject(err) }) }) } }
将其封装为一个类,而不是一个函数。
因为类可以创建多个实例,也就是说可以访问完全不同的服务器的接口。
其中可能出现的问题
Cannot find module ‘axios;‘ or its corresponding type declarations.ts(2307)
我想通过不同的运行环境创建不同的实例,所以设置如下
创建.env
文件
根据vue-cli 模式与环境变量官方写到,可根据env后指定mode即可创建不同的请求路径
创建.env.development
——用于开发环境
NODE_ENV = development
VUE_APP_BASE_URL = "http://你的开发请求的地址"
创建.env.production
——用于正式部署环境
NODE_ENV = production
VUE_APP_BASE_URL = "http://正式部署时请求的地址"
创建实例
因为我根据不同环境去设置变量时候,地址名字都是VUE_APP_BASE_RUL
所以,可以根据此去创建axios请求的baseUrl
import Request from "./request";
/**
* process.env.VUE_APP_BASE_URL 根据NODE_ENV变化而变化
*/
const web: Request = new Request({
baseURL: process.env.VUE_APP_BASE_URL,
})
export default web
现在尝试在main.ts
中调用一个接口
import web from './utils/request/index'
web.request({
url: '/login',
})
.then((res) => {
console.log(res);
})
现在对request.ts
进行优化升级(添加拦截器+泛型——复用性)
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; // import type { AxiosInstance , AxiosResponse } from 'axios'; class Request { private instance: AxiosInstance | undefined constructor(requeseConfig: AxiosRequestConfig) { this.instance = axios.create(requeseConfig) // 全局请求拦截 this.instance.interceptors.request.use( (config) => { console.log("全局请求拦截的", config); return config }, (error) => { console.log("全局请求拦截失败", error); }, ) // 全局响应拦截 this.instance.interceptors.response.use( (res) => { // res 为AxiosResponse 类型,含有conig\data\headers\request\status\statusText属性 console.log("全局响应拦截的", res); return res.data // 只需要返回data即可 }, (error) => { console.log("全局响应失败拦截"); console.log(error.request); console.log(error.response); return error }, ) } request<T>(config: AxiosRequestConfig<T>): Promise<T> { return new Promise<T>((resolve, reject) => { /* eslint-disable */ this.instance?.request<any, T>(config) .then((res) => { resolve(res) }) .catch((err) => { reject(err) }) }) } } export default Request
再次在main.ts中调用
web.request({
url: '/login',
})
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
})
现在的结果
在创建的index.ts
中,添加token
import Request from "./request"; /** * process.env.VUE_APP_BASE_URL 根据NODE_ENV变化而变化 */ /* eslint-disable */ const token = String(window.localStorage.getItem('token')) const web: Request = new Request({ baseURL: process.env.VUE_APP_BASE_URL, timeout: process.env.VUE_APP_TIME_OUT, headers: { 'Content-Type': 'application/json', 'Accept': "application/json", 'Authorization': token, }, }) export default web
现在的请求结果
现在请求的接口,带上了token,便于后端进行权限控制
get(url: string) { return new Promise((resolve, reject) => { this.instance?.post(url) .then((res) => { resolve(res.data) }) .catch((err) => { reject(err.data) }) }) } post(url: string, data = {}) { return new Promise((resolve, reject) => { this.instance?.post(url, data) .then((res) => { resolve(res.data) }) .catch((err) => { reject(err.data) }) }) }
就是在这里,我自闭了好久根本搞不懂别人是怎么做的。
因为一开始我根本对axios和ts都没有一个理解和认知,所以对于更加抽象的封装就显得无能为力了。
然后我就开始尝试看之前我们项目的代码结合其他开源项目的操作,就想到直接传url
和data
并给data一个初始值。
因为我希望对项目进行模块化的封装,于是创建了专门封装接口的api文件夹,文件夹下根据模块新建文件夹。
这里以user模块下的login为例
在api模块下,我创建了models.ts
,里面存放所有与后端对应接口的类型接口
例如:
后端的登录接口可以接受参数login包括
于是在userModels.ts
下定义接口如下
// 登录接口
export interface login {
accountEmail: string,
accountPassword: string,
code: string,
data: string,
}
同样的继续创建login.ts
文件,去实现接口
代码如下:
import web from "@/utils/request";
import { login } from "../models";
export default function login(requesrData?: login) {
const responesData = web.post('/login', requesrData)
return responesData;
}
?:
去定义类型
在对应的页面进行调用接口
<template> <button @click="login">来吧,试试一个接口看看</button> </template> <script setup lang='ts'> import login from '@/api/user/login'; const a = 1; console.log(a); const login= async () => { await login({ accountEmail: "xx@qq.com", accountPassword: "xxxxxxxxxxxxxx", code: "2xl4", data: "1647152454419", } </script> <style scoped> </style>
若是不满足定义的类型,则会报错
但是!!!这里注意的是
虽然静态报错,但是依旧可以运行成功!!!,暂时还没有找到解决办法阻断运行
总结
运行成功~
成功的那一刻是喜悦的!!!毕竟这算是自己独立封装出来的
虽然可能一些可拓展性存在缺陷,但终究结果也是可以接受的。这次用TS去封装axios有点快要自闭的感觉,自己对这些东西理解不深,然后看那些为了可扩展性和高复用性进行高度抽象的封装,就有些不知所措了,而且在这个过程中,自己没有及时的去真正尝试去理解。
而是只有当真正走投无路的时候,才开始去尝试其他的方法,有点过度依赖博客的感觉!
最后成功其实是借鉴了一些类似Vue3+TS的开源项目的封装思想。
所以这也提醒了我一个问题,当在百度中找不到你想要答案的时候,去看看其他人同类型的项目,获取就会豁然开朗
毕竟,一个程序员都是从借鉴学习开始的!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。