@sqin/http-client-uni
v1.0.3
Published
uni app 的 网络请求封装
Downloads
1
Readme
readme
uni app 的 网络请求封装
// api/index.ts
import { HttpClient, type HttpClientHooks } from "@sqin/http-client-uni";
const SOTRAGE_KEY_API_TOKEN = "api_token";
const SOTRAGE_KEY_LOGIN_TOKEN = "refresh_token";
export const setApiToken = (token: string) =>
uni.setStorageSync(SOTRAGE_KEY_API_TOKEN, token);
export const setLoginToken = (token: string) =>
uni.setStorageSync(SOTRAGE_KEY_LOGIN_TOKEN, token);
export const getApiToken = () => uni.getStorageSync(SOTRAGE_KEY_API_TOKEN);
export const getLoginToken = () => uni.getStorageSync(SOTRAGE_KEY_LOGIN_TOKEN);
type UniResponse = UniNamespace.RequestSuccessCallbackResult;
class HttpClientError extends Error {
showToast: boolean;
constructor(message: string, showToast = true) {
super(message);
this.showToast = showToast;
}
}
// ----------------------------------------------------------------
const hooks: HttpClientHooks = {
async urlHook(url) {
return "http://127.0.0.1:3000" + url;
},
async beforeRequest(option) {
const api_token = getApiToken();
if (api_token) {
option.header = {
Authorization: `Bearer ${api_token}`,
...option.header,
};
}
return option;
},
async responsePass(res, info) {
console.log("response pass", res);
const { statusCode } = res;
try {
if (statusCode >= 200 && statusCode < 300) {
return onResponseHandler.two(res, info);
}
if (statusCode >= 400 && statusCode < 500) {
return onResponseHandler.four(res, info);
}
if (statusCode >= 500 && statusCode < 600) {
return onResponseHandler.five(res, info);
}
throw new HttpClientError("未处理的 http code" + statusCode, false);
} catch (e) {
if (e instanceof HttpClientError) {
if (e.showToast)
uni.showToast({
title: e.message,
icon: "error",
});
}
}
},
async responseFail(err) {
// {errno: 600009, errMsg: "request:fail invalid url "/api/v1/login""}
console.log("response faild", err);
uni.showToast({
title: err?.errMsg || "无法访问服务器,请稍后在试",
});
throw err;
},
};
const onResponseHandler = {
async two(res: UniResponse, info: any) {
if (res.statusCode === 200) {
// 对 Response 数据进行一次校准,避免数据异常
if (typeof res?.data !== "object") {
// 说明格式可能错误
console.log("异常 res.data ", res.data);
throw new HttpClientError("数据异常");
}
return res.data;
}
throw new HttpClientError("未处理的 Http Code:" + res.statusCode, false);
},
async four(res: UniResponse, info: any) {
const { errMsg } = res;
// 鉴权
if (res.statusCode === 401) {
return Unauthorized(res, info);
}
let msg = res?.data?.msg || errMsg || "Code 400:操作失败";
throw new HttpClientError(msg);
},
five(res: UniResponse, info: any) {
const { errMsg } = res;
let msg = res.data?.msg || errMsg || "Code 500:服务器异常,请稍后在尝试";
throw new HttpClientError(msg);
},
};
const Unauthorized = async (res: UniResponse, info: any) => {
const token = getLoginToken();
if (!token) throw new HttpClientError("未登录");
const url = await hooks.urlHook?.("/api/v1/renew");
if (!url) throw new HttpClientError("url构建失败", false);
const renew = await defaultHttpClient.request({
url,
method: "POST",
data: {
refresh: token,
},
});
if (renew.statusCode !== 200)
throw new HttpClientError("自动刷新 Token 失败", false);
const { data } = renew.data as any;
const { api, refresh } = data;
// save 逻辑应该放在 pinia
if (api) setApiToken(api);
if (refresh) setLoginToken(refresh);
const { url: reqUrl, data: reqData } = info.config;
if (info.method === "GET") {
return defaultHttpClient.get(reqUrl, reqData);
} else {
return defaultHttpClient.post(reqUrl, reqData);
}
};
// ----------------------------------------------------------------
const defaultHttpClient = new HttpClient(hooks);
// ----------------------------------------------------------------
export const post = defaultHttpClient.post;
export const get = defaultHttpClient.get;
import { post } from "./index";
interface IHttpResponse<T = any> {
code: number;
ok: boolean;
msg: string;
data?: T;
[key: string]: any;
}
interface IResLogin {
api: string;
refresh: string;
}
export const reqLogin = (user = "王五") =>
post<IHttpResponse<IResLogin>>("/api/v1/login", {
user,
});