import { __awaiter } from "tslib"; import { NoopObject, addTrailingSlash, queryString, removeHeadingSlash, } from "@dage/utils"; import { createHeader } from "./Header"; import { stringReplace, variableReplace } from "./replace"; import { detectContentType, headersToObject, methodsHasBody, serializeBody, serializeResponseBody, } from "./utils"; import { ResponseError } from "./error"; const DEFAULT_INTERCEPTOR = (_, next) => { return next(); }; export function createService() { let adapter; let initialized = false; /** * 是否初始化完成 * @returns */ function isInitialized() { return initialized; } /** * 获取 Base URL */ function getBaseURL() { if (!initialized) { throw new Error("未初始化"); } return adapter.baseURL; } /** * 解析响应 */ function parseResponse(response) { var _a, _b; if (response == null) { throw { message: "未能识别响应", code: -1, }; } if (response.code !== 0) { throw new ResponseError(Object.assign(Object.assign({}, response), { errorMessage: (_a = response.errorMessage) !== null && _a !== void 0 ? _a : "请求失败", errorCode: (_b = response.errorCode) !== null && _b !== void 0 ? _b : -1 })); } return response; } /** * 初始化 * @param options */ function initial(options) { if (initialized && process.env.NODE_ENV === "development") { console.error("[@dage/service] 已经初始化过了, 不需要重复初始化"); } adapter = options; adapter.baseURL = addTrailingSlash(options.baseURL); initialized = true; } function normalizeRequest(url, body, config = NoopObject) { var _a, _b, _c; return __awaiter(this, void 0, void 0, function* () { if (!initialized) { throw new Error("请先调用 initial 初始化"); } const method = (_a = config.method) !== null && _a !== void 0 ? _a : "POST"; const searchParams = {}; const reqBody = body !== null && body !== void 0 ? body : NoopObject; // 路由参数替换 url = stringReplace(url, reqBody); // 查询字符串处理 const appendSearchParams = (obj, params = searchParams) => { Object.assign(params, obj); }; if (config.searchParams) { appendSearchParams(config.searchParams); } // 报头处理 const headers = createHeader(); if (config.headers) { Object.keys(config.headers).forEach((key) => { headers[key] = config.headers[key]; }); } if (methodsHasBody(method) && !headers["Content-Type"]) { const contentType = detectContentType(reqBody); if (contentType) { headers["Content-type"] = contentType; } } const requestPayload = { name: url, method, body: reqBody, searchParams, headers, meta: (_b = config.meta) !== null && _b !== void 0 ? _b : NoopObject, }; // 变量替换 if (adapter.globalVariables) { variableReplace(requestPayload.body, adapter.globalVariables); variableReplace(requestPayload.searchParams, adapter.globalVariables); variableReplace(requestPayload.headers, adapter.globalVariables); } const interceptor = (_c = adapter.interceptor) !== null && _c !== void 0 ? _c : DEFAULT_INTERCEPTOR; // next 方法被拦截器调用的次数,如果调用次数过多,说明程序存在bug,不排除有无限循环的可能 let nextCallTime = 0; const response = yield interceptor(requestPayload, () => __awaiter(this, void 0, void 0, function* () { nextCallTime++; // 最多 3 次 if (nextCallTime > 3) { throw new Error("拦截器调用 next 次数过多, 请检查代码,可能存在无限循环"); } if (requestPayload.body && requestPayload.method === "GET") { appendSearchParams(requestPayload.body, requestPayload.searchParams); } // 构建 href let href = url.startsWith("http") ? url : adapter.baseURL + removeHeadingSlash(url); if (Object.keys(requestPayload.searchParams).length) { const temp = queryString.parseUrl(href); href = queryString.stringifyUrl({ url: temp.url, query: Object.assign(Object.assign({}, temp.query), requestPayload.searchParams), fragmentIdentifier: temp.fragmentIdentifier, }); } /** * 主体处理 */ const finalBody = requestPayload.body && methodsHasBody(requestPayload.method) ? serializeBody(requestPayload.headers, requestPayload.body) : undefined; const res = yield adapter.fetch(href, { method: requestPayload.method, headers: requestPayload.headers, body: finalBody, mode: "cors", }); if (!res.ok) { console.error(res); throw new Error(`[@dage/service]请求 ${url} 失败: ${res.status}`); } const resData = yield serializeResponseBody(res, config); // @ts-expect-error const clone = Object.assign(Object.assign({}, resData), { // 原始请求信息 __raw__: { statusCode: res.status, data: resData, header: headersToObject(res.headers), } }); return clone; })); // 解析协议 return parseResponse(response); }); } /** * 请求方法,默认使用 POST 方法 */ function request(url, body, config) { return __awaiter(this, void 0, void 0, function* () { return (yield normalizeRequest(url, body, config)).data; }); } const requestByPost = request; function requestByGet(url, body, config) { return __awaiter(this, void 0, void 0, function* () { return (yield normalizeRequest(url, body, Object.assign({ method: "GET" }, config))) .data; }); } /** * 列表接口请求, 默认为 POST 请求 */ function requestPagination(name, body, config) { return __awaiter(this, void 0, void 0, function* () { return (yield normalizeRequest(name, body, Object.assign({ method: "POST" }, config))); }); } return { getBaseURL, parseResponse, initial, isInitialized, request, requestByPost, requestByGet, requestPagination, }; } const DEFAULT_SERVICE = createService(); /** * 获取 Base URL * @returns */ export const getBaseURL = DEFAULT_SERVICE.getBaseURL; /** * 解析响应 * @param response * @returns */ export const parseResponse = DEFAULT_SERVICE.parseResponse; /** * 是否初始化完成 * @returns */ export const isInitialized = DEFAULT_SERVICE.isInitialized; /** * 初始化 * @param options */ export const initial = DEFAULT_SERVICE.initial; export const request = DEFAULT_SERVICE.request; export const requestByPost = DEFAULT_SERVICE.requestByPost; export const requestByGet = DEFAULT_SERVICE.requestByGet; export const requestPagination = DEFAULT_SERVICE.requestPagination;