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 };