Path: blob/master/node_modules/axios/lib/adapters/xhr.js
1126 views
'use strict';12var utils = require('./../utils');3var settle = require('./../core/settle');4var cookies = require('./../helpers/cookies');5var buildURL = require('./../helpers/buildURL');6var buildFullPath = require('../core/buildFullPath');7var parseHeaders = require('./../helpers/parseHeaders');8var isURLSameOrigin = require('./../helpers/isURLSameOrigin');9var createError = require('../core/createError');10var defaults = require('../defaults');11var Cancel = require('../cancel/Cancel');1213module.exports = function xhrAdapter(config) {14return new Promise(function dispatchXhrRequest(resolve, reject) {15var requestData = config.data;16var requestHeaders = config.headers;17var responseType = config.responseType;18var onCanceled;19function done() {20if (config.cancelToken) {21config.cancelToken.unsubscribe(onCanceled);22}2324if (config.signal) {25config.signal.removeEventListener('abort', onCanceled);26}27}2829if (utils.isFormData(requestData)) {30delete requestHeaders['Content-Type']; // Let the browser set it31}3233var request = new XMLHttpRequest();3435// HTTP basic authentication36if (config.auth) {37var username = config.auth.username || '';38var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';39requestHeaders.Authorization = 'Basic ' + btoa(username + ':' + password);40}4142var fullPath = buildFullPath(config.baseURL, config.url);43request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);4445// Set the request timeout in MS46request.timeout = config.timeout;4748function onloadend() {49if (!request) {50return;51}52// Prepare the response53var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;54var responseData = !responseType || responseType === 'text' || responseType === 'json' ?55request.responseText : request.response;56var response = {57data: responseData,58status: request.status,59statusText: request.statusText,60headers: responseHeaders,61config: config,62request: request63};6465settle(function _resolve(value) {66resolve(value);67done();68}, function _reject(err) {69reject(err);70done();71}, response);7273// Clean up request74request = null;75}7677if ('onloadend' in request) {78// Use onloadend if available79request.onloadend = onloadend;80} else {81// Listen for ready state to emulate onloadend82request.onreadystatechange = function handleLoad() {83if (!request || request.readyState !== 4) {84return;85}8687// The request errored out and we didn't get a response, this will be88// handled by onerror instead89// With one exception: request that using file: protocol, most browsers90// will return status as 0 even though it's a successful request91if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {92return;93}94// readystate handler is calling before onerror or ontimeout handlers,95// so we should call onloadend on the next 'tick'96setTimeout(onloadend);97};98}99100// Handle browser request cancellation (as opposed to a manual cancellation)101request.onabort = function handleAbort() {102if (!request) {103return;104}105106reject(createError('Request aborted', config, 'ECONNABORTED', request));107108// Clean up request109request = null;110};111112// Handle low level network errors113request.onerror = function handleError() {114// Real errors are hidden from us by the browser115// onerror should only fire if it's a network error116reject(createError('Network Error', config, null, request));117118// Clean up request119request = null;120};121122// Handle timeout123request.ontimeout = function handleTimeout() {124var timeoutErrorMessage = config.timeout ? 'timeout of ' + config.timeout + 'ms exceeded' : 'timeout exceeded';125var transitional = config.transitional || defaults.transitional;126if (config.timeoutErrorMessage) {127timeoutErrorMessage = config.timeoutErrorMessage;128}129reject(createError(130timeoutErrorMessage,131config,132transitional.clarifyTimeoutError ? 'ETIMEDOUT' : 'ECONNABORTED',133request));134135// Clean up request136request = null;137};138139// Add xsrf header140// This is only done if running in a standard browser environment.141// Specifically not if we're in a web worker, or react-native.142if (utils.isStandardBrowserEnv()) {143// Add xsrf header144var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?145cookies.read(config.xsrfCookieName) :146undefined;147148if (xsrfValue) {149requestHeaders[config.xsrfHeaderName] = xsrfValue;150}151}152153// Add headers to the request154if ('setRequestHeader' in request) {155utils.forEach(requestHeaders, function setRequestHeader(val, key) {156if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {157// Remove Content-Type if data is undefined158delete requestHeaders[key];159} else {160// Otherwise add header to the request161request.setRequestHeader(key, val);162}163});164}165166// Add withCredentials to request if needed167if (!utils.isUndefined(config.withCredentials)) {168request.withCredentials = !!config.withCredentials;169}170171// Add responseType to request if needed172if (responseType && responseType !== 'json') {173request.responseType = config.responseType;174}175176// Handle progress if needed177if (typeof config.onDownloadProgress === 'function') {178request.addEventListener('progress', config.onDownloadProgress);179}180181// Not all browsers support upload events182if (typeof config.onUploadProgress === 'function' && request.upload) {183request.upload.addEventListener('progress', config.onUploadProgress);184}185186if (config.cancelToken || config.signal) {187// Handle cancellation188// eslint-disable-next-line func-names189onCanceled = function(cancel) {190if (!request) {191return;192}193reject(!cancel || (cancel && cancel.type) ? new Cancel('canceled') : cancel);194request.abort();195request = null;196};197198config.cancelToken && config.cancelToken.subscribe(onCanceled);199if (config.signal) {200config.signal.aborted ? onCanceled() : config.signal.addEventListener('abort', onCanceled);201}202}203204if (!requestData) {205requestData = null;206}207208// Send the request209request.send(requestData);210});211};212213214