关于前端:axios源码八

40次阅读

共计 5028 个字符,预计需要花费 13 分钟才能阅读完成。

今日来看 axios 发送申请的局部, 在 axios 中被称为适配器, 即配置中的 adapter 属性.
adapter 属性有两个值, 在浏览器中应用 xhr 文件, 在 node 中
在 xhr 文件中, 应用的其实就是 ajax, 也就是 XMLHttpRequest 这个办法.

    var request = new XMLHttpRequest();

当中就有咱们很相熟的 open 办法(request.open), onreadystatechange 办法(request.onreadystatechange), onabort 办法(request.onabort), 还有 onerror, ontimeout 等办法. 文件增加了一些判断, 使得申请更为欠缺. 间接上代码, 都看的懂

'use strict';

var utils = require('./../utils');
var settle = require('./../core/settle');
var cookies = require('./../helpers/cookies');
var buildURL = require('./../helpers/buildURL');
var buildFullPath = require('../core/buildFullPath');
var parseHeaders = require('./../helpers/parseHeaders');
var isURLSameOrigin = require('./../helpers/isURLSameOrigin');
var createError = require('../core/createError');

module.exports = function xhrAdapter(config) {return new Promise(function dispatchXhrRequest(resolve, reject) {
    var requestData = config.data;
    var requestHeaders = config.headers;

    if (utils.isFormData(requestData)) {delete requestHeaders['Content-Type']; // Let the browser set it  让浏览器来设置
    }

    var request = new XMLHttpRequest();

    // HTTP basic authentication   http 的根底验证
    if (config.auth) {
      var username = config.auth.username || '';
      var password = config.auth.password ? unescape(encodeURIComponent(config.auth.password)) : '';
      requestHeaders.Authorization = 'Basic' + btoa(username + ':' + password);
    }

    var fullPath = buildFullPath(config.baseURL, config.url);
    request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true);

    // Set the request timeout in MS  设置申请超时
    request.timeout = config.timeout;

    // Listen for ready state  监听 ready state
    request.onreadystatechange = function handleLoad() {if (!request || request.readyState !== 4) {return;}

      // The request errored out and we didn't get a response, this will be  
      // handled by onerror instead  申请谬误没有失去响应, 将会被 onerror 解决
      // With one exception: request that using file: protocol, most browsers
      // will return status as 0 even though it's a successful request  有一个例外, 大多数浏览器即便申请胜利也会返回状态为 0
      if (request.status === 0 && !(request.responseURL && request.responseURL.indexOf('file:') === 0)) {return;}

      // Prepare the response  筹备响应
      var responseHeaders = 'getAllResponseHeaders' in request ? parseHeaders(request.getAllResponseHeaders()) : null;
      var responseData = !config.responseType || config.responseType === 'text' ? request.responseText : request.response;
      var response = {
        data: responseData,
        status: request.status,
        statusText: request.statusText,
        headers: responseHeaders,
        config: config,
        request: request
      };

      settle(resolve, reject, response);

      // Clean up request  革除申请
      request = null;
    };

    // Handle browser request cancellation (as opposed to a manual cancellation)   解决浏览器申请勾销操作
    request.onabort = function handleAbort() {if (!request) {return;}

      reject(createError('Request aborted', config, 'ECONNABORTED', request));

      // Clean up request
      request = null;
    };

    // Handle low level network errors  解决低级网络谬误
    request.onerror = function handleError() {
      // Real errors are hidden from us by the browser  浏览器会为咱们暗藏真正的谬误
      // onerror should only fire if it's a network error   如果是个网络谬误会触发 onerror
      reject(createError('Network Error', config, null, request));

      // Clean up request
      request = null;
    };

    // Handle timeout 解决超时
    request.ontimeout = function handleTimeout() {
      var timeoutErrorMessage = 'timeout of' + config.timeout + 'ms exceeded';
      if (config.timeoutErrorMessage) {timeoutErrorMessage = config.timeoutErrorMessage;}
      reject(createError(timeoutErrorMessage, config, 'ECONNABORTED',
        request));

      // Clean up request
      request = null;
    };

    // Add xsrf header  
    // This is only done if running in a standard browser environment. 只有在规范浏览器环境下才会实现
    // Specifically not if we're in a web worker, or react-native.  在 web worker 或者 rn 中不会
    if (utils.isStandardBrowserEnv()) {
      // Add xsrf header
      var xsrfValue = (config.withCredentials || isURLSameOrigin(fullPath)) && config.xsrfCookieName ?
        cookies.read(config.xsrfCookieName) :
        undefined;

      if (xsrfValue) {requestHeaders[config.xsrfHeaderName] = xsrfValue;
      }
    }

    // Add headers to the request  给申请增加头部
    if ('setRequestHeader' in request) {utils.forEach(requestHeaders, function setRequestHeader(val, key) {if (typeof requestData === 'undefined' && key.toLowerCase() === 'content-type') {
          // Remove Content-Type if data is undefined  如果 data 是 undefined, 移除 content-type
          delete requestHeaders[key];
        } else {
          // Otherwise add header to the request 否则增加申请头
          request.setRequestHeader(key, val);
        }
      });
    }

    // Add withCredentials to request if needed  如果须要则增加验证
    if (!utils.isUndefined(config.withCredentials)) {request.withCredentials = !!config.withCredentials;}

    // Add responseType to request if needed  如果须要, 增加响应类型
    if (config.responseType) {
      try {request.responseType = config.responseType;} catch (e) {
        // Expected DOMException thrown by browsers not compatible XMLHttpRequest Level 2.  
        // But, this can be suppressed for 'json' type as it can be parsed by default 'transformResponse' function.
        if (config.responseType !== 'json') {throw e;}
      }
    }

    // Handle progress if needed  处理过程
    if (typeof config.onDownloadProgress === 'function') {request.addEventListener('progress', config.onDownloadProgress);
    }

    // Not all browsers support upload events  不是所有的浏览器都反对上传事件
    if (typeof config.onUploadProgress === 'function' && request.upload) {request.upload.addEventListener('progress', config.onUploadProgress);  // XMLHttpRequest 的 upload 属性
    }

    if (config.cancelToken) {
      // Handle cancellation  勾销操作
      config.cancelToken.promise.then(function onCanceled(cancel) {if (!request) {return;}

        request.abort();
        reject(cancel);
        // Clean up request
        request = null;
      });
    }

    if (!requestData) {requestData = null;}

    // Send the request
    request.send(requestData);
  });
};

正文完
 0