@xingm/http-request-sdk
v0.2.3
Published
Reusable axios request SDK for Vue 3 applications.
Readme
HTTP Request SDK
一个可发布到 npm 的 axios 请求 SDK,保留统一的请求拦截、响应码处理和错误处理逻辑,把 token、登录失效、UI 提示这些业务差异改成回调交给接入项目自己处理。
安装
npm install @xingm/http-request-sdk如果你要使用内置的 Ant Design Vue UI 适配器,再安装:
npm install ant-design-vue推荐用法
推荐在应用启动时初始化一次,后续所有普通模块都直接使用 request,不依赖 Vue 注入上下文。
// src/request.ts
import { request, setupRequestSdk } from "http-request-sdk";
import { message as antdMessage } from "ant-design-vue";
import { userStore } from "@/store/user";
setupRequestSdk({
baseURL: "/admin-api",
unwrapData: true,
getAccessToken: () => userStore.token,
refreshAccessToken: async () => {
const res = await fetch("/admin-api/system/auth/refresh-token", {
method: "POST",
credentials: "include",
}).then((r) => r.json());
userStore.setToken(res.data.accessToken);
return {
accessToken: res.data.accessToken,
};
},
onTokenExpired: () => {
userStore.logout();
location.href = "/login";
},
onBusinessError: ({ message }) => {
antdMessage.error(message);
},
onHttpError: ({ message }) => {
antdMessage.error(message);
},
});
export { request };// 任意 api 文件
import { request } from "@/request";
export const getUserList = () => request.get<User[]>("/system/user/list");510 微前端事件
当接口返回业务码 510 且当前处于微前端环境时,SDK 支持直接按配置调用对应的微前端事件中心。
资源子应用:
setupRequestSdk({
baseURL: "/admin-api",
authorization: {
eventCenterName: "eventCenterForResourceVite",
microAppName: "vmicro-app-resource",
},
});UAV 子应用:
setupRequestSdk({
baseURL: "/admin-api",
authorization: {
eventCenterName: "eventCenterForUAVCtrlVite",
microAppName: "vmicro-app-uavctrl",
},
});这样 SDK 会自动执行:
window[eventCenterName]?.dispatch({
myname: microAppName,
data: {
type: "authorization_expired",
machineCode,
expireTime,
},
});如果你不想直接调事件中心,也可以继续使用浏览器事件模式:
setupRequestSdk({
baseURL: "/admin-api",
authorization: {
eventName: "resource:authorization-expired",
},
});主应用没有 microAppName 和 eventCenterName 时,可以直接接管 510 处理:
setupRequestSdk({
baseURL: "/admin-api",
authorization: {
onExpired: ({ machineCode, expireTime, rawData }) => {
// 打开主应用自己的授权弹窗或页面
},
},
});Vue 项目用法
如果你仍然希望注册成 Vue 插件,也可以。插件安装时会自动设置默认实例,所以:
- 组件里可以用
useRequestSdk() - 普通模块里也可以直接
import { request } from "http-request-sdk"
// main.ts
import { createApp } from "vue";
import App from "./App.vue";
import { createRequestSdkPlugin } from "http-request-sdk/vue";
const app = createApp(App);
app.use(
createRequestSdkPlugin({
baseURL: "/admin-api",
unwrapData: true,
}),
);
app.mount("#app");// 组件内
import { useRequestSdk } from "http-request-sdk/vue";
const { request } = useRequestSdk();核心配置
最常用的配置就是这些:
setupRequestSdk({
baseURL: "/admin-api",
timeout: 30000,
lang: "zh-CN",
headers: {
tenantId: "xxx",
},
unwrapData: true,
successCodes: [0, 200],
authHeaderName: "Authorization",
authScheme: "Bearer",
getAccessToken: () => localStorage.getItem("token"),
getLocale: () => localStorage.getItem("locale"),
shouldRefreshToken: (response) => Number(response.data.code) === 401,
refreshAccessToken: async ({ service }) => {
const res = await service.post("/system/auth/refresh-token");
return {
accessToken: res.data.accessToken,
};
},
onTokenExpired: () => {
location.href = "/login";
},
onBusinessError: ({ code, message }) => {
reportBusinessError(code, message);
},
onHttpError: ({ code, message }) => {
reportHttpError(code, message);
},
});国际化
SDK 内置默认文案支持 zh-CN 和 en-US,接入项目可以通过 lang 指定:
setupRequestSdk({
baseURL: "/admin-api",
lang: "en-US",
});lang 只用于 SDK 内置提示文案,不会自动拼到接口 URL 或请求参数中,也不会自动作为请求头发送。如果需要发送语言请求头,请显式配置 getLocale 或 locale.getLocale。
如果项目已有自己的 i18n,可以继续使用 locale.translate,它的优先级高于 lang 内置文案:
setupRequestSdk({
lang: "zh-CN",
locale: {
translate: (key, defaultMessage) => i18n.global.t(key) || defaultMessage,
},
});请求参数格式
SDK 同时兼容对象式和分参式写法:
request.get({ url: "/system/user/list", params: { pageNo: 1 } });
request.get("/system/user/list", { pageNo: 1 });
request.post({ url: "/system/user/create", data: formData });
request.post("/system/user/create", formData);
request.post({ url: "/system/user/list", params: { pageNo: 1 } });
request.delete({ url: "/system/user/delete", params: { id: 1 } });
request.delete("/system/user/delete", { id: 1 });如果第二个参数是 axios config,比如 { params, headers, responseType },SDK 会保留原样传给 axios。
导出能力
主入口:
setupRequestSdk(options):创建并注册默认实例。request:默认实例的请求方法代理。http:默认实例的 axios 实例代理。createRequestSdk(options):手动创建独立实例。getDefaultRequestSdk():获取默认实例。
Vue 入口:
createRequestSdkPlugin(options)useRequestSdk()
适配器:
createAntDesignVueUiAdapter()createStorageTokenAdapter()
内置处理逻辑
- 自动注入 token 和语言头。
- 业务成功码默认支持
0和200。 - 业务码
401默认走刷新 token 流程,并复用并发刷新请求。 - 业务码
403统一按无权限处理。 - 业务码
510在微前端环境下支持直接按eventCenterName + microAppName调用window.xxx.dispatch(...);如果未配置,则默认抛出浏览器事件http-request-sdk:authorization-expired。 - blob 导出错误自动解析成业务错误。
- 保留旧版
token、ui、authorization配置,便于已有项目渐进迁移。
发布
npm run build
npm pack当前包名:
{
"name": "http-request-sdk"
}举例:vmicro-app-detection项目中使用方法
1.找到项目中的axios或者http.ts
2.将代码改为
import { request, setupRequestSdk } from "http-request-sdk";
import { message as antdMessage } from "ant-design-vue";
import { useUserStore } from "@/store/modules/user";
import { createAntDesignVueUiAdapter } from "http-request-sdk/adapters/ant-design-vue";
setupRequestSdk({
baseURL: "/admin-api",
ui: createAntDesignVueUiAdapter(),
unwrapData: true,
authorization: {
eventCenterName: "eventCenterForUAVCtrlVite", 各子应用定义的事件名
microAppName: "vmicro-app-detection", 子应用名称
},
getAccessToken: () => localStorage.getItem('token'), 用store或者localStorage,根据子应用各自判断
refreshAccessToken: async () => {
const refreshToken = localStorage.getItem('refreshToken')
const res = await fetch(/admin-api/system/auth/refresh-token?refreshToken=${refreshToken}, {
method: "POST",
credentials: "include",
}).then((r) => r.json());
localStorage.setItem('token', res.data.accessToken);
localStorage.setItem('refreshToken', res.data.refreshToken);
return {
accessToken: res.data.accessToken,
refreshToken: res.data.refreshToken,
};}, onTokenExpired: () => { const userStore = useUserStore(); userStore .logout() .then(() => { window.location.reload() }) .catch(() => { }); }, onBusinessError: ({ message }) => { antdMessage.error(message); }, onHttpError: ({ message }) => { antdMessage.error(message); }, }); const defHttp = request export { defHttp };
