304 lines
10 KiB
JavaScript
304 lines
10 KiB
JavaScript
import loggerIns from "./logger";
|
||
export class NetError extends Error {
|
||
code;
|
||
message;
|
||
httpStatus;
|
||
constructor({ code, message, httpStatus }) {
|
||
super(message);
|
||
this.code = code;
|
||
this.message = message;
|
||
this.httpStatus = httpStatus;
|
||
}
|
||
}
|
||
/**
|
||
* 网络工具类,提供发送HTTP请求的方法。
|
||
*/
|
||
class NetToolBase {
|
||
prefix;
|
||
headers;
|
||
getHeaders;
|
||
logger;
|
||
requestId;
|
||
/**
|
||
* 创建一个网络工具类实例。
|
||
*
|
||
* @param {Object} params - 构造函数参数。
|
||
* @param {string} [params.prefix] - URL前缀。
|
||
* @param {any} [params.headers] - 默认请求头。
|
||
* @param {Function} [params.getHeaders] - 获取请求头的方法。
|
||
* @param {string} [params.requestId] - 请求ID。
|
||
*/
|
||
constructor({ prefix, headers, getHeaders, requestId, } = {}) {
|
||
this.prefix = prefix || "";
|
||
this.headers = headers || {};
|
||
this.getHeaders = getHeaders || (() => ({}));
|
||
this.requestId = requestId || "";
|
||
this.logger = loggerIns.child({ requestId });
|
||
}
|
||
/**
|
||
* 记录响应详情并返回响应日志对象。
|
||
* @param response - 响应对象。
|
||
* @param method - 请求使用的HTTP方法。
|
||
* @param headers - 请求头。
|
||
* @param requestBody - 请求体。
|
||
* @param responseBody - 响应体。
|
||
* @returns 响应日志对象。
|
||
*/
|
||
logResponse(response, method, headers, requestBody, responseBody) {
|
||
const responseLog = {
|
||
ok: response.ok,
|
||
status: response.status,
|
||
statusText: response.statusText,
|
||
url: response.url,
|
||
method: method,
|
||
requestHeaders: headers,
|
||
responseHeaders: response.headers,
|
||
requestBody,
|
||
responseBody,
|
||
};
|
||
this.logger.http(JSON.stringify(responseLog, null, 2));
|
||
return responseLog;
|
||
}
|
||
/**
|
||
* 发送网络请求并返回一个解析为响应数据的Promise。
|
||
* @param url - 要发送请求的URL。
|
||
* @param method - 请求使用的HTTP方法。
|
||
* @param queryParams - 要包含在URL中的查询参数。
|
||
* @param payload - 请求的有效负载数据。
|
||
* @param additionalHeaders - 要包含在请求中的附加头。
|
||
* @returns 一个解析为响应数据的Promise。
|
||
* @throws 如果网络响应不成功或存在解析错误,则抛出错误。
|
||
*/
|
||
async request({ url, method, queryParams, payload, additionalHeaders, }) {
|
||
// 拼接完整的URL
|
||
let fullUrl = `${this.prefix}${url}`;
|
||
if (queryParams) {
|
||
if (typeof queryParams === "string") {
|
||
fullUrl = `${fullUrl}?${queryParams}`;
|
||
}
|
||
else {
|
||
const queryString = new URLSearchParams(queryParams).toString();
|
||
if (queryString)
|
||
fullUrl = `${fullUrl}?${queryString}`;
|
||
}
|
||
}
|
||
// 设置请求头
|
||
const headers = {
|
||
...this.headers,
|
||
...(await this.getHeaders()),
|
||
...additionalHeaders,
|
||
};
|
||
// 设置请求Header
|
||
if (!(payload instanceof FormData)) {
|
||
headers["Content-Type"] = "application/json";
|
||
}
|
||
// 处理请求数据
|
||
const body = payload instanceof FormData ? payload : JSON.stringify(payload);
|
||
// 发送请求
|
||
const res = await fetch(fullUrl, {
|
||
method,
|
||
body,
|
||
headers,
|
||
});
|
||
// 获取响应数据
|
||
let resData = null;
|
||
let resText = "";
|
||
try {
|
||
resText = await res.text();
|
||
resData = JSON.parse(resText);
|
||
}
|
||
catch {
|
||
/* empty */
|
||
}
|
||
// 记录响应
|
||
this.logResponse(res, method, headers, payload, resData || resText);
|
||
if (!res.ok) {
|
||
if (resData?.message || resData?.msg) {
|
||
throw new NetError({
|
||
httpStatus: res.status,
|
||
code: resData?.code,
|
||
message: resData?.message || resData?.msg,
|
||
});
|
||
}
|
||
throw new NetError({
|
||
httpStatus: res.status,
|
||
code: res.status,
|
||
message: resText || "网络响应异常",
|
||
});
|
||
}
|
||
// http 错误码正常,但解析异常
|
||
if (!resData) {
|
||
throw new NetError({
|
||
httpStatus: res.status,
|
||
code: 1,
|
||
message: "解析响应数据异常",
|
||
});
|
||
}
|
||
// 响应数据异常
|
||
if ("code" in resData && resData.code !== 0) {
|
||
throw new NetError({
|
||
httpStatus: res.status,
|
||
code: resData.code,
|
||
message: resData.message || resData.msg || "网络请求失败",
|
||
});
|
||
}
|
||
return resData;
|
||
}
|
||
/**
|
||
* 发送GET请求并返回一个解析为响应数据的Promise。
|
||
*
|
||
* @param url - 要发送请求的URL。
|
||
* @param queryParams - 要包含在URL中的查询参数。
|
||
* @param additionalHeaders - 要包含在请求中的附加头。
|
||
* @returns 一个解析为响应数据的Promise。
|
||
*/
|
||
get(url, queryParams, additionalHeaders) {
|
||
return this.request({ url, method: "get", queryParams, additionalHeaders });
|
||
}
|
||
/**
|
||
* 发送POST请求并返回一个解析为响应数据的Promise。
|
||
*
|
||
* @param url - 要发送请求的URL。
|
||
* @param payload - 请求的有效负载数据。
|
||
* @param queryParams - 要包含在URL中的查询参数。
|
||
* @param additionalHeaders - 要包含在请求中的附加头。
|
||
* @returns 一个解析为响应数据的Promise。
|
||
*/
|
||
post(url, payload, queryParams, additionalHeaders) {
|
||
return this.request({
|
||
url,
|
||
method: "post",
|
||
payload,
|
||
queryParams,
|
||
additionalHeaders,
|
||
});
|
||
}
|
||
/**
|
||
* 发送PUT请求并返回一个解析为响应数据的Promise。
|
||
*
|
||
* @param url - 要发送请求的URL。
|
||
* @param payload - 请求的有效负载数据。
|
||
* @param queryParams - 要包含在URL中的查询参数。
|
||
* @param additionalHeaders - 要包含在请求中的附加头。
|
||
* @returns 一个解析为响应数据的Promise。
|
||
*/
|
||
put(url, payload, queryParams, additionalHeaders) {
|
||
return this.request({
|
||
url,
|
||
method: "put",
|
||
payload,
|
||
queryParams,
|
||
additionalHeaders,
|
||
});
|
||
}
|
||
/**
|
||
* 发送DELETE请求并返回一个解析为响应数据的Promise。
|
||
*
|
||
* @param url - 要发送请求的URL。
|
||
* @param payload - 请求的有效负载数据。
|
||
* @param queryParams - 要包含在URL中的查询参数。
|
||
* @param additionalHeaders - 要包含在请求中的附加头。
|
||
* @returns 一个解析为响应数据的Promise。
|
||
*/
|
||
del(url, payload, queryParams, additionalHeaders) {
|
||
return this.request({
|
||
url,
|
||
method: "delete",
|
||
payload,
|
||
queryParams,
|
||
additionalHeaders,
|
||
});
|
||
}
|
||
/**
|
||
* 发送PATCH请求并返回一个解析为响应数据的Promise。
|
||
*
|
||
* @param url - 要发送请求的URL。
|
||
* @param payload - 请求的有效负载数据。
|
||
* @param queryParams - 要包含在URL中的查询参数。
|
||
* @param additionalHeaders - 要包含在请求中的附加头。
|
||
* @returns 一个解析为响应数据的Promise。
|
||
*/
|
||
patch(url, payload, queryParams, additionalHeaders) {
|
||
return this.request({
|
||
url,
|
||
method: "patch",
|
||
payload,
|
||
queryParams,
|
||
additionalHeaders,
|
||
});
|
||
}
|
||
}
|
||
class NetTool extends NetToolBase {
|
||
request({ url, method, queryParams, payload, additionalHeaders, }) {
|
||
return super.request({
|
||
url,
|
||
method,
|
||
queryParams,
|
||
payload,
|
||
additionalHeaders,
|
||
});
|
||
}
|
||
get(url, queryParams, additionalHeaders) {
|
||
return super.get(url, queryParams, additionalHeaders);
|
||
}
|
||
post(url, payload, queryParams, additionalHeaders) {
|
||
return super.post(url, payload, queryParams, additionalHeaders);
|
||
}
|
||
put(url, payload, queryParams, additionalHeaders) {
|
||
return super.put(url, payload, queryParams, additionalHeaders);
|
||
}
|
||
del(url, payload, queryParams, additionalHeaders) {
|
||
return super.del(url, payload, queryParams, additionalHeaders);
|
||
}
|
||
patch(url, payload, queryParams, additionalHeaders) {
|
||
return super.patch(url, payload, queryParams, additionalHeaders);
|
||
}
|
||
/**
|
||
* 创建一个表示400 Bad Request的响应对象。
|
||
*
|
||
* @param message - 错误消息。
|
||
* @returns 一个表示400 Bad Request的响应对象。
|
||
*/
|
||
badRequest(message) {
|
||
this.logger.error(`return a bad request response: ${message}`);
|
||
return Response.json({ code: 400, message, requestId: this.requestId }, { status: 400 });
|
||
}
|
||
/**
|
||
* 创建一个表示404 Not Found的响应对象。
|
||
*
|
||
* @param message - 错误消息。
|
||
* @returns 一个表示404 Not Found的响应对象。
|
||
*/
|
||
notFound(message) {
|
||
this.logger.error(`return a not found response: ${message}`);
|
||
return Response.json({ code: 404, message, requestId: this.requestId }, { status: 404 });
|
||
}
|
||
/**
|
||
* 创建一个表示500 Internal Server Error的响应对象。
|
||
*
|
||
* @param message - 错误消息。
|
||
* @param data - 错误数据。
|
||
* @returns 一个表示500 Internal Server Error的响应对象。
|
||
*/
|
||
serverError(message, data) {
|
||
this.logger.error(`return a server error response: ${message}`);
|
||
return Response.json({ code: 500, message, data, requestId: this.requestId }, { status: 500 });
|
||
}
|
||
/**
|
||
* 创建一个表示200 OK的响应对象。
|
||
*
|
||
* @param data - 响应数据。
|
||
* @returns 一个表示200 OK的响应对象。
|
||
*/
|
||
ok(data) {
|
||
this.logger.info(`return a ok response: ${JSON.stringify(data)}`);
|
||
return Response.json({
|
||
code: 0,
|
||
message: "success",
|
||
data,
|
||
requestId: this.requestId,
|
||
});
|
||
}
|
||
}
|
||
export { NetTool, NetToolBase };
|