request.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.request = exports.axios = void 0;
  7. const chalk_1 = __importDefault(require("chalk"));
  8. const axios_1 = __importDefault(require("axios"));
  9. const psl_1 = require("psl");
  10. const set_cookie_parser_1 = require("set-cookie-parser");
  11. const DEF_TIMEOUT = 10000;
  12. const DEF_MAX_RETRIES = 2;
  13. const DEF_WITH_SET_COOKIES = false;
  14. const DEF_UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.80 Safari/537.36';
  15. exports.axios = axios_1.default.create({
  16. headers: {
  17. 'user-agent': DEF_UA
  18. },
  19. withCredentials: true
  20. });
  21. class CookieController {
  22. static parseHostToDomains(host) {
  23. const domains = [host, `.${host}`];
  24. const domain = psl_1.get(host);
  25. if (domain && domain !== host) {
  26. domains.push(domain, `.${domain}`);
  27. }
  28. return domains;
  29. }
  30. static sync(setCookies, host) {
  31. const cookies = set_cookie_parser_1.parse(setCookies);
  32. for (const item of cookies) {
  33. console.debug(chalk_1.default.white(`└─ set-cookie`, JSON.stringify(item)));
  34. const { name, domain = host } = item;
  35. const cached = this.cacheMap.get(domain) || [];
  36. const existIndex = cached.findIndex(c => c.name === name);
  37. if (existIndex > -1) {
  38. cached.splice(existIndex, 1, item);
  39. }
  40. else {
  41. cached.push(item);
  42. }
  43. this.cacheMap.set(domain, cached);
  44. }
  45. }
  46. static inject(url, headers) {
  47. const domains = this.parseHostToDomains(new URL(url).host);
  48. const cookies = [];
  49. const now = Date.now();
  50. for (const domain of domains) {
  51. const cache = this.cacheMap.get(domain);
  52. if (cache) {
  53. const cookieStrs = cache
  54. .filter(c => !c.expires || c.expires.valueOf() > now)
  55. .map(c => `${c.name}=${c.value}`);
  56. cookies.push(...cookieStrs);
  57. }
  58. }
  59. const cookie = (headers.cookie ? `${headers.cookie}; ` : '') + cookies.join('; ');
  60. headers.cookie = cookie;
  61. cookie && console.debug(chalk_1.default.white(`└─ cookie:`, cookie));
  62. }
  63. }
  64. CookieController.cacheMap = new Map();
  65. const request = (config, retries = 0) => {
  66. config.timeout = config.timeout || DEF_TIMEOUT;
  67. config.maxRetries = config.maxRetries || DEF_MAX_RETRIES;
  68. config.withSetCookies = config.withSetCookies != null ? config.withSetCookies : DEF_WITH_SET_COOKIES;
  69. const _config = JSON.stringify(config);
  70. const fullUrl = `${config.baseURL || exports.axios.defaults.baseURL || ''}${config.url}`;
  71. const cancelTokenSource = axios_1.default.CancelToken.source();
  72. config.cancelToken = cancelTokenSource.token;
  73. config.headers = config.headers || {};
  74. console.debug(chalk_1.default.white(`[request] ${config.method || 'GET'} ${fullUrl}`, config.params ? JSON.stringify(config.params) : ''));
  75. if (config.withSetCookies) {
  76. CookieController.inject(fullUrl, config.headers);
  77. }
  78. return new Promise((resolve, reject) => {
  79. let done = false;
  80. const timer = setTimeout(() => {
  81. if (!done) {
  82. cancelTokenSource.cancel();
  83. // @ts-ignore
  84. if (retries >= config.maxRetries) {
  85. reject(new Error(`max retries exceeded (${retries})`));
  86. }
  87. else {
  88. retries++;
  89. console.info(chalk_1.default.magenta(`[request] ${config.url} timeouted, canceled, retry ${retries}`));
  90. resolve(exports.request(JSON.parse(_config), retries));
  91. }
  92. }
  93. }, config.timeout);
  94. const startAt = Date.now();
  95. exports.axios(config)
  96. .then((res) => {
  97. console.debug(chalk_1.default.white(`└─ ${res.status} ${Date.now() - startAt}ms`));
  98. const setCookies = res.headers['set-cookie'];
  99. if (config.withSetCookies && setCookies) {
  100. const { host } = new URL(res.request.res.responseUrl);
  101. CookieController.sync(setCookies, host);
  102. }
  103. resolve(res);
  104. })
  105. .catch((e) => {
  106. if (e.response && e.response.data) {
  107. console.error('[error.message]', e.message);
  108. console.error('[error.response]', e.response.data);
  109. }
  110. reject(e);
  111. })
  112. .finally(() => {
  113. done = true;
  114. clearTimeout(timer);
  115. });
  116. });
  117. };
  118. exports.request = request;