request.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import { __awaiter } from "tslib";
  2. import { NoopObject, addTrailingSlash, queryString, removeHeadingSlash, } from "@dage/utils";
  3. import { createHeader } from "./Header";
  4. import { stringReplace, variableReplace } from "./replace";
  5. import { detectContentType, headersToObject, methodsHasBody, serializeBody, serializeResponseBody, } from "./utils";
  6. import { ResponseError } from "./error";
  7. const DEFAULT_INTERCEPTOR = (_, next) => {
  8. return next();
  9. };
  10. export function createService() {
  11. let adapter;
  12. let initialized = false;
  13. /**
  14. * 是否初始化完成
  15. * @returns
  16. */
  17. function isInitialized() {
  18. return initialized;
  19. }
  20. /**
  21. * 获取 Base URL
  22. */
  23. function getBaseURL() {
  24. if (!initialized) {
  25. throw new Error("未初始化");
  26. }
  27. return adapter.baseURL;
  28. }
  29. /**
  30. * 解析响应
  31. */
  32. function parseResponse(response) {
  33. var _a, _b;
  34. if (response == null) {
  35. throw {
  36. message: "未能识别响应",
  37. code: -1,
  38. };
  39. }
  40. if (response.code !== 0) {
  41. 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 }));
  42. }
  43. return response;
  44. }
  45. /**
  46. * 初始化
  47. * @param options
  48. */
  49. function initial(options) {
  50. if (initialized && process.env.NODE_ENV === "development") {
  51. console.error("[@dage/service] 已经初始化过了, 不需要重复初始化");
  52. }
  53. adapter = options;
  54. adapter.baseURL = addTrailingSlash(options.baseURL);
  55. initialized = true;
  56. }
  57. function normalizeRequest(url, body, config = NoopObject) {
  58. var _a, _b, _c;
  59. return __awaiter(this, void 0, void 0, function* () {
  60. if (!initialized) {
  61. throw new Error("请先调用 initial 初始化");
  62. }
  63. const method = (_a = config.method) !== null && _a !== void 0 ? _a : "POST";
  64. const searchParams = {};
  65. const reqBody = body !== null && body !== void 0 ? body : NoopObject;
  66. // 路由参数替换
  67. url = stringReplace(url, reqBody);
  68. // 查询字符串处理
  69. const appendSearchParams = (obj, params = searchParams) => {
  70. Object.assign(params, obj);
  71. };
  72. if (config.searchParams) {
  73. appendSearchParams(config.searchParams);
  74. }
  75. // 报头处理
  76. const headers = createHeader();
  77. if (config.headers) {
  78. Object.keys(config.headers).forEach((key) => {
  79. headers[key] = config.headers[key];
  80. });
  81. }
  82. if (methodsHasBody(method) && !headers["Content-Type"]) {
  83. const contentType = detectContentType(reqBody);
  84. if (contentType) {
  85. headers["Content-type"] = contentType;
  86. }
  87. }
  88. const requestPayload = {
  89. name: url,
  90. method,
  91. body: reqBody,
  92. searchParams,
  93. headers,
  94. meta: (_b = config.meta) !== null && _b !== void 0 ? _b : NoopObject,
  95. };
  96. // 变量替换
  97. if (adapter.globalVariables) {
  98. variableReplace(requestPayload.body, adapter.globalVariables);
  99. variableReplace(requestPayload.searchParams, adapter.globalVariables);
  100. variableReplace(requestPayload.headers, adapter.globalVariables);
  101. }
  102. const interceptor = (_c = adapter.interceptor) !== null && _c !== void 0 ? _c : DEFAULT_INTERCEPTOR;
  103. // next 方法被拦截器调用的次数,如果调用次数过多,说明程序存在bug,不排除有无限循环的可能
  104. let nextCallTime = 0;
  105. const response = yield interceptor(requestPayload, () => __awaiter(this, void 0, void 0, function* () {
  106. nextCallTime++;
  107. // 最多 3 次
  108. if (nextCallTime > 3) {
  109. throw new Error("拦截器调用 next 次数过多, 请检查代码,可能存在无限循环");
  110. }
  111. if (requestPayload.body && requestPayload.method === "GET") {
  112. appendSearchParams(requestPayload.body, requestPayload.searchParams);
  113. }
  114. // 构建 href
  115. let href = url.startsWith("http")
  116. ? url
  117. : adapter.baseURL + removeHeadingSlash(url);
  118. if (Object.keys(requestPayload.searchParams).length) {
  119. const temp = queryString.parseUrl(href);
  120. href = queryString.stringifyUrl({
  121. url: temp.url,
  122. query: Object.assign(Object.assign({}, temp.query), requestPayload.searchParams),
  123. fragmentIdentifier: temp.fragmentIdentifier,
  124. });
  125. }
  126. /**
  127. * 主体处理
  128. */
  129. const finalBody = requestPayload.body && methodsHasBody(requestPayload.method)
  130. ? serializeBody(requestPayload.headers, requestPayload.body)
  131. : undefined;
  132. const res = yield adapter.fetch(href, {
  133. method: requestPayload.method,
  134. headers: requestPayload.headers,
  135. body: finalBody,
  136. mode: "cors",
  137. });
  138. if (!res.ok) {
  139. console.error(res);
  140. throw new Error(`[@dage/service]请求 ${url} 失败: ${res.status}`);
  141. }
  142. const resData = yield serializeResponseBody(res, config);
  143. // @ts-expect-error
  144. const clone = Object.assign(Object.assign({}, resData), {
  145. // 原始请求信息
  146. __raw__: {
  147. statusCode: res.status,
  148. data: resData,
  149. header: headersToObject(res.headers),
  150. } });
  151. return clone;
  152. }));
  153. // 解析协议
  154. return parseResponse(response);
  155. });
  156. }
  157. /**
  158. * 请求方法,默认使用 POST 方法
  159. */
  160. function request(url, body, config) {
  161. return __awaiter(this, void 0, void 0, function* () {
  162. return (yield normalizeRequest(url, body, config)).data;
  163. });
  164. }
  165. const requestByPost = request;
  166. function requestByGet(url, body, config) {
  167. return __awaiter(this, void 0, void 0, function* () {
  168. return (yield normalizeRequest(url, body, Object.assign({ method: "GET" }, config)))
  169. .data;
  170. });
  171. }
  172. /**
  173. * 列表接口请求, 默认为 POST 请求
  174. */
  175. function requestPagination(name, body, config) {
  176. return __awaiter(this, void 0, void 0, function* () {
  177. return (yield normalizeRequest(name, body, Object.assign({ method: "POST" }, config)));
  178. });
  179. }
  180. return {
  181. getBaseURL,
  182. parseResponse,
  183. initial,
  184. isInitialized,
  185. request,
  186. requestByPost,
  187. requestByGet,
  188. requestPagination,
  189. };
  190. }
  191. const DEFAULT_SERVICE = createService();
  192. /**
  193. * 获取 Base URL
  194. * @returns
  195. */
  196. export const getBaseURL = DEFAULT_SERVICE.getBaseURL;
  197. /**
  198. * 解析响应
  199. * @param response
  200. * @returns
  201. */
  202. export const parseResponse = DEFAULT_SERVICE.parseResponse;
  203. /**
  204. * 是否初始化完成
  205. * @returns
  206. */
  207. export const isInitialized = DEFAULT_SERVICE.isInitialized;
  208. /**
  209. * 初始化
  210. * @param options
  211. */
  212. export const initial = DEFAULT_SERVICE.initial;
  213. export const request = DEFAULT_SERVICE.request;
  214. export const requestByPost = DEFAULT_SERVICE.requestByPost;
  215. export const requestByGet = DEFAULT_SERVICE.requestByGet;
  216. export const requestPagination = DEFAULT_SERVICE.requestPagination;