xhr.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. 'use strict';
  2. var utils = require('./../utils');
  3. var settle = require('./../core/settle');
  4. var cookies = require('./../helpers/cookies');
  5. var buildURL = require('./../helpers/buildURL');
  6. var buildFullPath = require('../core/buildFullPath');
  7. var parseHeaders = require('./../helpers/parseHeaders');
  8. var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
  9. var createError = require('../core/createError');
  10. module.exports = function xhrAdapter(config) {
  11. return new Promise(function dispatchXhrRequest(resolve, reject) {
  12. var requestData = config.data;
  13. var requestHeaders = config.headers;
  14. if (utils.isFormData(requestData)) {
  15. delete requestHeaders['Content-Type']; // Let the browser set it
  16. }
  17. var request = new XMLHttpRequest();
  18. // HTTP basic authentication
  19. if (config.auth) {
  20. var username = config.auth.username || '';
  21. var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
  22. requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);
  23. }
  24. var fullPath = buildFullPath(config.baseURL, config.url);
  25. request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);
  26. // Set the request timeout in MS
  27. request.timeout = config.timeout;
  28. // Listen for ready state
  29. request.onreadystatechange = function handleLoad() {
  30. if (!request || request.readyState !== 4) {
  31. return;
  32. }
  33. // The request errored out and we didn't get a response, this will be
  34. // handled by onerror instead
  35. // With one exception: request that using file: protocol, most browsers
  36. // will return status as 0 even though it's a successful request
  37. if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {
  38. return;
  39. }
  40. // Prepare the response
  41. var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
  42. var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
  43. var response = {
  44. data: responseData,
  45. status: request.status,
  46. statusText: request.statusText,
  47. headers: responseHeaders,
  48. config: config,
  49. request: request
  50. };
  51. settle(resolve, reject, response);
  52. // Clean up request
  53. request = null;
  54. };
  55. // Handle browser request cancellation (as opposed to a manual cancellation)
  56. request.onabort = function handleAbort() {
  57. if (!request) {
  58. return;
  59. }
  60. reject(createError('Request aborted', config, 'ECONNABORTED', request));
  61. // Clean up request
  62. request = null;
  63. };
  64. // Handle low level network errors
  65. request.onerror = function handleError() {
  66. // Real errors are hidden from us by the browser
  67. // onerror should only fire if it's a network error
  68. reject(createError('Network Error', config, null, request));
  69. // Clean up request
  70. request = null;
  71. };
  72. // Handle timeout
  73. request.ontimeout = function handleTimeout() {
  74. var timeoutErrorMessage = 'timeout of ' + config.timeout + 'ms exceeded';
  75. if (config.timeoutErrorMessage) {
  76. timeoutErrorMessage = config.timeoutErrorMessage;
  77. }
  78. reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
  79. request));
  80. // Clean up request
  81. request = null;
  82. };
  83. // Add xsrf header
  84. // This is only done if running in a standard browser environment.
  85. // Specifically not if we're in a web worker, or react-native.
  86. if (utils.isStandardBrowserEnv()) {
  87. // Add xsrf header
  88. var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
  89. cookies.read(config.xsrfCookieName) :
  90. undefined;
  91. if (xsrfValue) {
  92. requestHeaders[config.xsrfHeaderName] = xsrfValue;
  93. }
  94. }
  95. // Add headers to the request
  96. if ('setRequestHeader' in request) {
  97. utils.forEach(requestHeaders, function setRequestHeader(val, key) {
  98. if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
  99. // Remove Content-Type if data is undefined
  100. delete requestHeaders[key];
  101. } else {
  102. // Otherwise add header to the request
  103. request.setRequestHeader(key, val);
  104. }
  105. });
  106. }
  107. // Add withCredentials to request if needed
  108. if (!utils.isUndefined(config.withCredentials)) {
  109. request.withCredentials = !!config.withCredentials;
  110. }
  111. // Add responseType to request if needed
  112. if (config.responseType) {
  113. try {
  114. request.responseType = config.responseType;
  115. } catch (e) {
  116. // Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.
  117. // But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
  118. if (config.responseType !== 'json') {
  119. throw e;
  120. }
  121. }
  122. }
  123. // Handle progress if needed
  124. if (typeof config.onDownloadProgress === 'function') {
  125. request.addEventListener('progress', config.onDownloadProgress);
  126. }
  127. // Not all browsers support upload events
  128. if (typeof config.onUploadProgress === 'function' && request.upload) {
  129. request.upload.addEventListener('progress', config.onUploadProgress);
  130. }
  131. if (config.cancelToken) {
  132. // Handle cancellation
  133. config.cancelToken.promise.then(function onCanceled(cancel) {
  134. if (!request) {
  135. return;
  136. }
  137. request.abort();
  138. reject(cancel);
  139. // Clean up request
  140. request = null;
  141. });
  142. }
  143. if (!requestData) {
  144. requestData = null;
  145. }
  146. // Send the request
  147. request.send(requestData);
  148. });
  149. };