数据联调
开发环境
如果前端应用和后端接口服务器没有运行在同一个主机上,你需要在开发环境下将接口请求代理到接口服务器。
如果是同一个主机,可以直接请求具体的接口地址。
配置
开发环境时候,接口地址在项目根目录下
.env.development 文件配置
# vite 本地跨域代理
VITE_PROXY=[["/api","https://xxx.test.com"]]
# 接口地址通用前缀
VITE_GLOB_API_URL=/manage
TIP
- .env 文件中的字段如果是字符串,则无需加引号,默认全部为字符串
- VITE_PROXY 不能换行
跨域处理
如果你在 src/api/
下面的接口为下方代码,且 .env.development 文件配置如下注释,则在控制台看到的地址为 https://xxx.test.com/api/manage/auth/index
。
由于 /api
匹配到了设置的 VITE_PROXY
,所以上方实际是请求 **https://xxx.test.com/manage//auth/index**,这样同时也解决了跨域问题。
跨域原理解析
在 vite.config.ts
配置文件中,提供了 server 的 proxy 功能,用于代理 API 请求。
server: {
proxy: {
"/api":{
target: 'https://xxx.test.com',
changeOrigin: true,
ws: true,
rewrite: (path) => path.replace(new RegExp(`^/api`), ''),
}
},
},
注意
从浏览器控制台的 Network 看,请求是 https://xxx.test.com/api/xxx
,这是因为 proxy 配置不会改变本地请求的 url。
生产环境
生产环境接口地址在项目根目录下 .env.production 文件配置。
生产环境接口地址值需要修改 VITE_GLOB_API_URL
如果出现跨域问题,可以使用 nginx 或者后台开启 cors 进行处理, 或者前段处理
打包后如何进行地址修改?
VITE_GLOB_* 开头的变量会在打包的时候注入 _app.config.js 文件内。
在 dist/_app.config.js 修改相应的接口地址后刷新页面即可,不需要在根据不同环境打包多次,一次打包可以用于多个不同接口环境的部署。
接口请求
进行了特别复杂的封装, 使代码更加模块化, 参考了vben项目
在 vite-project 中:
- 页面交互操作;
- 调用统一管理的 api 请求函数;
- 使用封装的 axios.ts 发送请求;
- 获取服务端返回数据
- 更新 data;
接口统一存放于 src/api/ 下面管理
以菜单为例:
在 src/api/ 内新建模块文件,其中参数与返回值最好定义一下类型,方便校验。虽然麻烦,但是后续维护字段很方便。
TIP
类型定义文件可以抽取出去统一管理,具体参考项目
import { IMenuData } from '#/router';
import { defHttp } from '@/http/axios';
enum Api {
authList = '/auth/index',
}
// 角色-列表
export function api_manage_auth_list() {
return defHttp.get<Result<Record<'table_list', IMenuData[]>>>({url: Api.authList});
}
axios 配置
axios 请求封装存放于 src/http/axios 文件夹内部
二次封装的 axios
暴露出了 4个方法
export declare abstract class CustomAxiosTransform {
customRequest?: (config: AxiosRequestConfig) => AxiosRequestConfig; // 自定义请求拦截
customResponse?: (config: AxiosResponse<any>) => AxiosResponse<any>; // 自定义相应拦截
customRequestError?: (error: Error) => void; // 自定义请求错误拦截
customResponseError?: (error: Error) => void; // 自定义相应错误拦截
}
除 index.ts
文件内容需要根据项目自行修改外,其余文件无需修改
├── index.ts // 引用二次封装的asiox
使用案例
enum Api {
roleList = '/manage/role/index'
}
export interface IRoleAuths {
id:string;
init_auth_id: string;
init_auth_name: string;
remark: string;
role_name: string
}
// 角色-列表
export function api_manage_role_list() {
return defHttp.get<Result<Record<'table_list', IRoleAuths[]>>>({url: Api.roleList});
}
index.ts 配置说明
export const defHttp = createAxios({
timeout: 10 * 1000,
customTransform: {
customRequest: custom_request,
customRequestError: custom_request_error,
customResponse: custom_response,
customResponseError: custom_response_error
},
headers: {'Content-Type': ContentTypeEnum.JSON},
requestOptions: {
// 默认将prefix 添加到url
joinPrefix: true,
// 是否返回原生响应头 比如:需要获取响应头时使用该属性
isReturnNativeResponse: false,
// 消息提示类型
errorMessageMode: 'message',
// 接口地址
apiUrl: import.meta.env.VITE_GLOB_API_URL,
// 是否加入时间戳
joinTime: true,
// 是否在请求中加入环境参数
joinEnv: true,
// 忽略重复请求
cancelToken: true
}
});
transform 数据处理说明
类型定义,见 axiosTransform.ts 文件
export abstract class AxiosTransform {
/**
* @description: 请求之前处理配置
*/
beforeRequestHook?: (config: AxiosRequestConfig, options: RequestOptions) => AxiosRequestConfig;
/**
* @description: 请求之前的拦截器
*/
requestInterceptors?: (config: AxiosRequestConfig) => AxiosRequestConfig;
/**
* @description: 请求之后的拦截器
*/
responseInterceptors?: (res: AxiosResponse<any>) => AxiosResponse<any>;
/**
* @description: 请求之前的拦截器错误处理
*/
requestInterceptorsCatch?: (error: Error) => void;
/**
* @description: 请求之后的拦截器错误处理
*/
responseInterceptorsCatch?: (error: Error) => void;
}
更改参数格式
项目接口默认为 Json 参数格式,即 headers: { 'Content-Type': ContentTypeEnum.FORM_URLENCODED }
,
如果需要更改为 json
格式,更改 headers 的 'Content-Type
为 ContentTypeEnum.JSON
即可
多个接口地址
当项目中需要用到多个接口地址时, 可以在 src/utils/http/axios/index.ts 导出多个 axios 实例
// 目前只导出一个默认实例,接口地址对应的是环境变量中的 VITE_GLOB_API_URL 接口地址
export const defHttp = createAxios();
// 需要有其他接口地址的可以在后面添加
// other api url
export const otherHttp = createAxios({
requestOptions: {
apiUrl: 'xxx',
},
});
删除请求 URL 携带的时间戳参数
如果不需要 url 上面默认携带的时间戳参数 ?t=xxx
export const defHttp = createAxios({
requestOptions: {
// 是否加入时间戳
joinTime: false,
},
});
删除请求 URL 携带的环境参数
如果不需要 url 上面默认携带的环境参数 ?env=xxx
export const defHttp = createAxios({
requestOptions: {
// 是否加入时间戳
joinEnv: false,
},
});
Mock 服务
开发中