b47bb5a0a2ed9d12648a38e0c3b4581799f5cacab6ec6b751f72e815af569539c241299194c4ef7e8f311bff1922c35154e03f08d8ba0fa7e87f843845372e 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. import { AjaxRequest, AjaxResponseType } from './types';
  2. import { getXHRResponse } from './getXHRResponse';
  3. /**
  4. * A normalized response from an AJAX request. To get the data from the response,
  5. * you will want to read the `response` property.
  6. *
  7. * - DO NOT create instances of this class directly.
  8. * - DO NOT subclass this class.
  9. *
  10. * It is advised not to hold this object in memory, as it has a reference to
  11. * the original XHR used to make the request, as well as properties containing
  12. * request and response data.
  13. *
  14. * @see {@link ajax}
  15. * @see {@link AjaxConfig}
  16. */
  17. export class AjaxResponse<T> {
  18. /** The HTTP status code */
  19. readonly status: number;
  20. /**
  21. * The response data, if any. Note that this will automatically be converted to the proper type
  22. */
  23. readonly response: T;
  24. /**
  25. * The responseType set on the request. (For example: `""`, `"arraybuffer"`, `"blob"`, `"document"`, `"json"`, or `"text"`)
  26. * @deprecated There isn't much reason to examine this. It's the same responseType set (or defaulted) on the ajax config.
  27. * If you really need to examine this value, you can check it on the `request` or the `xhr`. Will be removed in v8.
  28. */
  29. readonly responseType: XMLHttpRequestResponseType;
  30. /**
  31. * The total number of bytes loaded so far. To be used with {@link total} while
  32. * calculating progress. (You will want to set {@link includeDownloadProgress} or
  33. * {@link includeDownloadProgress})
  34. */
  35. readonly loaded: number;
  36. /**
  37. * The total number of bytes to be loaded. To be used with {@link loaded} while
  38. * calculating progress. (You will want to set {@link includeDownloadProgress} or
  39. * {@link includeDownloadProgress})
  40. */
  41. readonly total: number;
  42. /**
  43. * A dictionary of the response headers.
  44. */
  45. readonly responseHeaders: Record<string, string>;
  46. /**
  47. * A normalized response from an AJAX request. To get the data from the response,
  48. * you will want to read the `response` property.
  49. *
  50. * - DO NOT create instances of this class directly.
  51. * - DO NOT subclass this class.
  52. *
  53. * @param originalEvent The original event object from the XHR `onload` event.
  54. * @param xhr The `XMLHttpRequest` object used to make the request. This is useful for examining status code, etc.
  55. * @param request The request settings used to make the HTTP request.
  56. * @param type The type of the event emitted by the {@link ajax} Observable
  57. */
  58. constructor(
  59. /**
  60. * The original event object from the raw XHR event.
  61. */
  62. public readonly originalEvent: ProgressEvent,
  63. /**
  64. * The XMLHttpRequest object used to make the request.
  65. * NOTE: It is advised not to hold this in memory, as it will retain references to all of it's event handlers
  66. * and many other things related to the request.
  67. */
  68. public readonly xhr: XMLHttpRequest,
  69. /**
  70. * The request parameters used to make the HTTP request.
  71. */
  72. public readonly request: AjaxRequest,
  73. /**
  74. * The event type. This can be used to discern between different events
  75. * if you're using progress events with {@link includeDownloadProgress} or
  76. * {@link includeUploadProgress} settings in {@link AjaxConfig}.
  77. *
  78. * The event type consists of two parts: the {@link AjaxDirection} and the
  79. * the event type. Merged with `_`, they form the `type` string. The
  80. * direction can be an `upload` or a `download` direction, while an event can
  81. * be `loadstart`, `progress` or `load`.
  82. *
  83. * `download_load` is the type of event when download has finished and the
  84. * response is available.
  85. */
  86. public readonly type: AjaxResponseType = 'download_load'
  87. ) {
  88. const { status, responseType } = xhr;
  89. this.status = status ?? 0;
  90. this.responseType = responseType ?? '';
  91. // Parse the response headers in advance for the user. There's really
  92. // not a great way to get all of them. So we need to parse the header string
  93. // we get back. It comes in a simple enough format:
  94. //
  95. // header-name: value here
  96. // content-type: application/json
  97. // other-header-here: some, other, values, or, whatever
  98. const allHeaders = xhr.getAllResponseHeaders();
  99. this.responseHeaders = allHeaders
  100. ? // Split the header text into lines
  101. allHeaders.split('\n').reduce((headers: Record<string, string>, line) => {
  102. // Split the lines on the first ": " as
  103. // "key: value". Note that the value could
  104. // technically have a ": " in it.
  105. const index = line.indexOf(': ');
  106. headers[line.slice(0, index)] = line.slice(index + 2);
  107. return headers;
  108. }, {})
  109. : {};
  110. this.response = getXHRResponse(xhr);
  111. const { loaded, total } = originalEvent;
  112. this.loaded = loaded;
  113. this.total = total;
  114. }
  115. }