四、Axios + Mock.js
前言
作为前后端分离的项目,必不可少的当然是发请求向后端拿数据了,由于一个人精力有限,我不打算前后端一起开发,主要原因是一起开发会导致,前端开发进度变慢,时间线拖长,会导致我本人激情的减退,最后可能这个项目就“太监”了。所以使用
mock.js
先模拟后端接口,等后面做后端开发的时候,可以无缝衔接,直接替换为真正的后端服务。
1. 引入 Aioxs
Axios
是一个基于promise
的网络请求库,进一步了解参考官方文档:axios-http.com/zh/
1.1 安装依赖
npm install axios
1.2 封装请求工具类
新建目录
src/utils
,新建文件request.ts
import axios from 'axios'
const instance = axios.create({
baseURL: '/api',
timeout: 5000
})
// 添加请求拦截器
instance.interceptors.request.use(
function (config) {
// 请求成功做点什么
return config
},
function (error) {
// 对请求错误做点什么
return Promise.reject(error)
}
)
// 添加响应拦截器
instance.interceptors.response.use(
function (response) {
// 对响应成功做点什么
return response
},
function (error) {
// 对响应错误做点什么
return Promise.reject(error)
}
)
export default instance
2. 引入 Mock.js
生成随机数据,拦截
Ajax
请求。进一步了解参考官方文档:mockjs.com/
2.1 安装依赖
npm install --save-dev mockjs @types/mockjs
2.2 新建 src/mock
目录,新建 mock.ts
定义一个
Mock
获取用户信息的数据
import type { UserInfo } from '@/types/user'
import Mock from 'mockjs'
// 获取用户信息
Mock.mock('/api/user', 'get', () => {
return {
code: 200,
success: true,
message: '请求成功。',
data: <UserInfo>{
id: '1',
username: 'admin',
avatar: ''
}
}
})
2.3 在 main.ts
中引入
import './mock/mock.ts'
2.4 新建文件夹 src/api
,新建文件 index.ts
,user.ts
这里用的是 ts 所以对于类型要求比较严格,所以要定义好我们生成数据的类型 新建 src/types 文件夹,
data.d.ts
中我定义了统一的一些类型,user.d.ts
则是用户相关的类型
//data.d.ts
// 所有的接口的通用类型
export interface ApiRes<T> {
success: boolean
code: string
data?: T
message: string
}
// 登录认证 token 信息
export interface Token {
accessToken: string
}
// user.d.ts
// 用户信息
export interface UserInfo {
id?: string
username?: string
avatar?: string
}
API接口定义
// api/user.ts
import type { UserInfo } from '@/types/user'
import request from '@/utils/request'
// 获取当前用户信息
export const getUserInfo = () => {
return request<UserInfo>({
method: 'GET',
url: '/user'
})
}
// api/index.ts
// 统一导出所有接口
import * as user from './user'
export default {
user
}
3. 测试
在
App.vue
页面 加个button
添加点击登录事件
<el-button type="primary" size="default" class="bg-green-500" @click="login">登录</el-button>
<script setup lang="ts">
import { RouterLink, RouterView } from 'vue-router'
import HelloWorld from './components/HelloWorld.vue'
import api from './api/index'
const login = () => {
api.user.getUserInfo().then((res) => {
console.log(res)
})
}
</script>
启动项目点击测试
可以看到,如我们所预期的那样拿到了结果。那么后面想要什么数据自己定义好接口返回就行了。
4. 一点点优化
我们想要拿到具体返回的内容,输入
res.data.
的时候由于ts
类型检测给了我们提示,如果打印res.data.id
,出来会是undefined
,因为从打印的res
结果可以知道,其实我们要拿的数据应该在,res.data.data
里。
我们改成
res.data.data.id
,成功取到值了,但是这个时候会发现vscode
爆红了,提示找不到类型
这里主要是因为,我们导出
axios
对象的时候,没有确定好类型,vscode
检测异常了, 而且在请求接口过程中,其实对于我们有用的信息就是最终的data
对象,所以这里在封装的request.ts
中,我们进行统一处理。
① 在响应拦截器中进行解构,返回 data
对象
// request.ts
// 添加响应拦截器
instance.interceptors.response.use(
function (response) {
const { success, message, data } = response.data
// 判断当前请求是否成功
if (success) {
return data
} else {
// 请求失败,业务失败,消息提示
return Promise.reject(new Error(message))
}
},
function (error) {
// 对响应错误做点什么
return Promise.reject(error)
}
)
② 再出 axios
对象的时候进行类型指定
// 指定返回数据类型,类型推断提示
export default <T = any>(config: AxiosRequestConfig) => {
return instance(config).then((data) => {
return data as T
})
}
这个时候再去刚才测试的地方发现直接通过返回对象就可以有提示信息,并且可成功拿到返回结果。 如果发现没有提示或者爆红,重启一下
vscode
。
思考
到这里基本配置已经可以了,但是这里我
baseURL
是写死的,'/api'
,我暂时打算通过这个来区分正式服务还是mock
服务,如果是/api
通过代理转到正式服务,如果是/mock
则转到mock
服务,然后通过环境配置文件.env.xxxx
去动态配置baseURL
,但是这样还有一个问题就是,我想同时使用mock
和 正式的服务,就没法弄了。其实最简单就是不要动baseURL
, 每一个接口定义两个,一个走正式,一个走mock
, 但是这样在环境切分上就要手动去改使用的方法,这是我不能接受的,暂时先留个坑,后面接入的时候再研究。
① 创建 .env.development
,注意这里的变量名必须以 VITE_
开头
# 标志
ENV = 'development'
# base api
VITE_APP_BASE_API = '/mock'
② 为我们自定义的变量添加类型扩展
// env.d.ts
// 扩展环境变量
interface ImportMetaEnv {
readonly VITE_APP_TITLE: string
readonly VITE_APP_PORT: number
readonly VITE_APP_BASE_API: string
// 更多环境变量...
}
interface ImportMeta {
readonly env: ImportMetaEnv
}
修改
request.ts
中的baseURL
,这时可以看到有提示。修改
mock.ts
中定义的接口,将前缀改成/mock
转载自:https://juejin.cn/post/7242475298678652988