httpclient.js 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. 'use strict';
  2. const Agent = require('agentkeepalive');
  3. const HttpsAgent = require('agentkeepalive').HttpsAgent;
  4. const urllib = require('urllib');
  5. const ms = require('humanize-ms');
  6. const { FrameworkBaseError } = require('egg-errors');
  7. class HttpClientError extends FrameworkBaseError {
  8. get module() {
  9. return 'httpclient';
  10. }
  11. }
  12. class HttpClient extends urllib.HttpClient2 {
  13. constructor(app) {
  14. normalizeConfig(app);
  15. const config = app.config.httpclient;
  16. super({
  17. app,
  18. defaultArgs: config.request,
  19. agent: new Agent(config.httpAgent),
  20. httpsAgent: new HttpsAgent(config.httpsAgent),
  21. });
  22. this.app = app;
  23. }
  24. request(url, args, callback) {
  25. if (typeof args === 'function') {
  26. callback = args;
  27. args = null;
  28. }
  29. args = args || {};
  30. if (args.ctx && args.ctx.tracer) {
  31. args.tracer = args.ctx.tracer;
  32. } else {
  33. args.tracer = args.tracer || this.app.tracer;
  34. }
  35. // the callback style
  36. if (callback) {
  37. this.app.deprecate('[httpclient] We now support async for this function, so callback isn\'t recommended.');
  38. super.request(url, args)
  39. .then(result => process.nextTick(() => callback(null, result.data, result.res)))
  40. .catch(err => process.nextTick(() => callback(err)));
  41. return;
  42. }
  43. // the Promise style
  44. return super.request(url, args)
  45. .catch(err => {
  46. if (err.code === 'ENETUNREACH') {
  47. throw HttpClientError.create(err.message, err.code);
  48. }
  49. throw err;
  50. });
  51. }
  52. curl(url, args, callback) {
  53. return this.request(url, args, callback);
  54. }
  55. requestThunk(url, args) {
  56. this.app.deprecate('[httpclient] Please use `request()` instead of `requestThunk()`');
  57. return callback => {
  58. this.request(url, args, (err, data, res) => {
  59. if (err) {
  60. return callback(err);
  61. }
  62. callback(null, {
  63. data,
  64. status: res.status,
  65. headers: res.headers,
  66. res,
  67. });
  68. });
  69. };
  70. }
  71. }
  72. function normalizeConfig(app) {
  73. const config = app.config.httpclient;
  74. // compatibility
  75. if (typeof config.keepAlive === 'boolean') {
  76. config.httpAgent.keepAlive = config.keepAlive;
  77. config.httpsAgent.keepAlive = config.keepAlive;
  78. }
  79. if (config.timeout) {
  80. config.timeout = ms(config.timeout);
  81. config.httpAgent.timeout = config.timeout;
  82. config.httpsAgent.timeout = config.timeout;
  83. }
  84. // compatibility httpclient.freeSocketKeepAliveTimeout => httpclient.freeSocketTimeout
  85. if (config.freeSocketKeepAliveTimeout && !config.freeSocketTimeout) {
  86. config.freeSocketTimeout = config.freeSocketKeepAliveTimeout;
  87. delete config.freeSocketKeepAliveTimeout;
  88. }
  89. if (config.freeSocketTimeout) {
  90. config.freeSocketTimeout = ms(config.freeSocketTimeout);
  91. config.httpAgent.freeSocketTimeout = config.freeSocketTimeout;
  92. config.httpsAgent.freeSocketTimeout = config.freeSocketTimeout;
  93. } else {
  94. // compatibility agent.freeSocketKeepAliveTimeout
  95. if (config.httpAgent.freeSocketKeepAliveTimeout && !config.httpAgent.freeSocketTimeout) {
  96. config.httpAgent.freeSocketTimeout = config.httpAgent.freeSocketKeepAliveTimeout;
  97. delete config.httpAgent.freeSocketKeepAliveTimeout;
  98. }
  99. if (config.httpsAgent.freeSocketKeepAliveTimeout && !config.httpsAgent.freeSocketTimeout) {
  100. config.httpsAgent.freeSocketTimeout = config.httpsAgent.freeSocketKeepAliveTimeout;
  101. delete config.httpsAgent.freeSocketKeepAliveTimeout;
  102. }
  103. }
  104. if (typeof config.maxSockets === 'number') {
  105. config.httpAgent.maxSockets = config.maxSockets;
  106. config.httpsAgent.maxSockets = config.maxSockets;
  107. }
  108. if (typeof config.maxFreeSockets === 'number') {
  109. config.httpAgent.maxFreeSockets = config.maxFreeSockets;
  110. config.httpsAgent.maxFreeSockets = config.maxFreeSockets;
  111. }
  112. if (config.httpAgent.timeout < 30000) {
  113. app.coreLogger.warn('[egg:httpclient] config.httpclient.httpAgent.timeout(%s) can\'t below 30000, auto reset to 30000',
  114. config.httpAgent.timeout);
  115. config.httpAgent.timeout = 30000;
  116. }
  117. if (config.httpsAgent.timeout < 30000) {
  118. app.coreLogger.warn('[egg:httpclient] config.httpclient.httpsAgent.timeout(%s) can\'t below 30000, auto reset to 30000',
  119. config.httpsAgent.timeout);
  120. config.httpsAgent.timeout = 30000;
  121. }
  122. if (typeof config.request.timeout === 'string') {
  123. config.request.timeout = ms(config.request.timeout);
  124. }
  125. }
  126. module.exports = HttpClient;