Fancy Front End Fancy Front End
  • 开始上手
  • 基础
  • 调度器(Scheduler)
  • 更新器(Updater)
  • 渲染器(Render)
  • 更新周期
  • hooks 原理
  • 总结
  • 📙 React源码漂流记
  • 开始上手
  • 基础
  • reactivity
  • runtime-core
  • runtime-dom
  • Awesome Web
  • Awesome NodeJS
话题
  • 导航
  • Q&A
  • 幻灯片
  • 关于
  • 分类
  • 标签
  • 归档
博客 (opens new window)
GitHub (opens new window)

Jonsam NG

让有意义的事变得有意思,让有意思的事变得有意义
  • 开始上手
  • 基础
  • 调度器(Scheduler)
  • 更新器(Updater)
  • 渲染器(Render)
  • 更新周期
  • hooks 原理
  • 总结
  • 📙 React源码漂流记
  • 开始上手
  • 基础
  • reactivity
  • runtime-core
  • runtime-dom
  • Awesome Web
  • Awesome NodeJS
话题
  • 导航
  • Q&A
  • 幻灯片
  • 关于
  • 分类
  • 标签
  • 归档
博客 (opens new window)
GitHub (opens new window)
  • 开始上手
  • Plan 计划
  • typescript-utility

  • single-spa源码

  • qiankun源码

  • webpack

  • axios

    • 开始阅读
    • core

      • 本章概要
      • axios 对象和方法
      • adapter 适配器
        • getDefaultAdapter
        • XHR Adapter
        • HTTP Adapter
      • interceptor 拦截器
      • cancel 取消请求
  • solid

  • vite源码

  • jquery源码

  • snabbdom

  • am-editor

  • html2canvas

  • express

  • acorn源码

  • immutable.js源码

  • web
  • axios
  • core
jonsam
2022-06-26
目录

adapter 适配器

# getDefaultAdapter

axios 如何根据运行环境先选择默认的 adapter 呢?

/**
 * If the browser has an XMLHttpRequest object, use the XHR adapter, otherwise use the HTTP
 * adapter
 *
 * @returns {Function}
 */
function getDefaultAdapter() {
  var adapter;
  if (typeof XMLHttpRequest !== 'undefined') {
    // For browsers use XHR adapter
    adapter = require('../adapters/xhr');
  } else if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
    // For node use HTTP adapter
    adapter = require('../adapters/http');
  }
  return adapter;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  • 如果支持 XMLHttpRequest,就是用 XHR。
  • 不支持 XHR 则使用 nodeJS 的 HTTP 模块。
  • 这两种方式分别用于 web 环境和 nodejs 环境。

# XHR Adapter

XHR Adapter 用于 web 环境。

function xhrAdapter(config) {
 return new Promise(function dispatchXhrRequest(resolve, reject) {
  var requestData = config.data;
  var requestHeaders = config.headers;
  var responseType = config.responseType;
  var onCanceled;
  // 删除取消请求的订阅,cancelToken或者signal是两种取消请求的方式
  function done() {
   if (config.cancelToken) {
    config.cancelToken.unsubscribe(onCanceled);
   }

   if (config.signal) {
    config.signal.removeEventListener("abort", onCanceled);
   }
  }

  if (utils.isFormData(requestData) && utils.isStandardBrowserEnv()) {
   delete requestHeaders["Content-Type"]; // Let the browser set it
  }

  var request = new XMLHttpRequest();

  // HTTP basic authentication
  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;

  function onloadend() {
   if (!request) {
    return;
   }
   // Prepare the response
   var responseHeaders =
    "getAllResponseHeaders" in request
     ? parseHeaders(request.getAllResponseHeaders())
     : null;
   var responseData =
    !responseType || responseType === "text" || responseType === "json"
     ? request.responseText
     : request.response;
   var response = {
    data: responseData,
    status: request.status,
    statusText: request.statusText,
    headers: responseHeaders,
    config: config,
    request: request,
   };

   settle(
    function _resolve(value) {
     resolve(value);
     done();
    },
    function _reject(err) {
     reject(err);
     done();
    },
    response
   );

   // Clean up request
   request = null;
  }

  if ("onloadend" in request) {
   // Use onloadend if available
   request.onloadend = onloadend;
  } else {
   // Listen for ready state to emulate onloadend
   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
    // With one exception: request that using file: protocol, most browsers
    // will return status as 0 even though it's a successful request
    if (
     request.status === 0 &&
     !(request.responseURL && request.responseURL.indexOf("file:") === 0)
    ) {
     return;
    }
    // readystate handler is calling before onerror or ontimeout handlers,
    // so we should call onloadend on the next 'tick'
    setTimeout(onloadend);
   };
  }

  // Handle browser request cancellation (as opposed to a manual cancellation)
  request.onabort = function handleAbort() {
   if (!request) {
    return;
   }

   reject(
    new AxiosError(
     "Request aborted",
     AxiosError.ECONNABORTED,
     config,
     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
   reject(
    new AxiosError("Network Error", AxiosError.ERR_NETWORK, config, request)
   );

   // Clean up request
   request = null;
  };

  // Handle timeout
  request.ontimeout = function handleTimeout() {
   var timeoutErrorMessage = config.timeout
    ? "timeout of " + config.timeout + "ms exceeded"
    : "timeout exceeded";
   var transitional = config.transitional || transitionalDefaults;
   if (config.timeoutErrorMessage) {
    timeoutErrorMessage = config.timeoutErrorMessage;
   }
   reject(
    new AxiosError(
     timeoutErrorMessage,
     transitional.clarifyTimeoutError
      ? AxiosError.ETIMEDOUT
      : AxiosError.ECONNABORTED,
     config,
     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.
  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
     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 (responseType && responseType !== "json") {
   request.responseType = config.responseType;
  }

  // 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);
  }

  if (config.cancelToken || config.signal) {
   // Handle cancellation
   // eslint-disable-next-line func-names
   onCanceled = function (cancel) {
    if (!request) {
     return;
    }
    reject(
     !cancel || cancel.type ? new CanceledError(null, config, req) : cancel
    );
    request.abort();
    request = null;
   };

   config.cancelToken && config.cancelToken.subscribe(onCanceled);
   if (config.signal) {
    config.signal.aborted
     ? onCanceled()
     : config.signal.addEventListener("abort", onCanceled);
   }
  }

  if (!requestData) {
   requestData = null;
  }

  var protocol = parseProtocol(fullPath);

  if (protocol && platform.protocols.indexOf(protocol) === -1) {
   reject(
    new AxiosError(
     "Unsupported protocol " + protocol + ":",
     AxiosError.ERR_BAD_REQUEST,
     config
    )
   );
   return;
  }

  // Send the request
  request.send(requestData);
 });
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257

xhrAdapter 的处理过程如下:

  1. 创建 XMLHttpRequest 。
  2. 根据 auth 配置添加 Authorization header。
  3. 计算发送请求的 url。
  4. request.open 配置请求。
  5. 设置 request.timeout 。
  6. 注册 onloadend 事件,支持 request.onloadend 则使用 request.onloadend ,使用使用 request.onreadystatechange 监听 request.readyState 为 4。
  7. 注册 request.onabort 事件,抛出 Request aborted 消息的 AxiosError 。
  8. 注册 request.onerror 事件,抛出 Network Error 消息的 AxiosError 。
  9. 注册 request.ontimeout 事件,抛出 timeout exceeded 消息的 AxiosError 。
  10. 在 web 环境中,如果配置了 xsrfCookieName,则将 xsrfCookieName 设置在 header 上作为预防 xsrf 攻击的 token。
  11. 处理请求的 headers。
  12. 处理 request.withCredentials 、 request.responseType 。
  13. 如果配置了 onDownloadProgress ,则在 request 上监听 progress 事件。
  14. 如果配置了 cancelToken 或者 signal ,前者在 cancelToken 上订阅 onCanceled ,后者监听 signal 的 abort 事件,触发 onCanceled 回调。 onCanceled 中抛出 CanceledError 错误,并且 request.abort 。
  15. 检查是否是支持的协议 protocol ,否则抛出 Unsupported protocol 错误的 AxiosError。
  16. 发送请求 request.send(requestData) 。
  17. 请求发出后, onloadend 处理 response 对象。通过验证 status 即 validateStatus resolve response 或者 reject 一个 Request failed AxiosError。validateStatus 默认的校验规则是 status >= 200 && status < 300 。
  18. onloadend 之后调用 done ,做 cleanup 的工作。

# HTTP Adapter

HTTP Adapter 用于 NodeJS 环境。

编辑 (opens new window)
上次更新: 2022/09/06, 14:25:16
axios 对象和方法
interceptor 拦截器

← axios 对象和方法 interceptor 拦截器→

最近更新
01
渲染原理之组件结构与 JSX 编译
09-07
02
计划跟踪
09-06
03
开始上手
09-06
更多文章>
Theme by Vdoing | Copyright © 2022-2022 Fancy Front End | Made by Jonsam by ❤
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式