Axios 源码解读 —— 网络请求篇

上一章我们介绍了 Axios 源码解读 —— request 篇,这一章我们来介绍 Axios 实际发起网络请求的部分吧,也就是 dispatchRequest 方法。

dispatchRequest

这个方法定义也比较简单(如下图)

image

第 29 行 —— 取消请求

我们来逐行解析每一行代码所做的事情吧,首先是第 29 行的取消请求。(如下)

throwIfCancellationRequested(config);

这个动作不仅仅在发起正式请求前做了一次,而且在请求成功和请求失败时都做了一次。

只要是被 cancel 的请求,都是不会进入到成功或失败回调处理中的。(如下图)

image

throwIfCancellationRequested 函数所做的事情,就是检测该请求是否被取消,如果被取消则抛出一个错误,并阻止代码继续向下执行。(如下)

function throwIfCancellationRequested(config) {
  if (config.cancelToken) {
    // 检测请求是否被取消,然后决定是否抛出错误
    config.cancelToken.throwIfRequested();
  }

  if (config.signal && config.signal.aborted) {
    // 抛出错误
    throw new Cancel('canceled');
  }
}

当然,整套 CancelToken 的实现还是有一些复杂的(复杂在回调处理),如果有人感兴趣的话,可以单独讲讲这一部分的处理,这里就先不做展开了。

第 35 ~ 40 行 —— 处理请求 data

config.data = transformData.call(
  config,
  config.data,
  config.headers,
  config.transformRequest
);

这里用到了一个 transformData 方法,主要的作用是合并 data,并且可以使用配置的 transformRequest 方法进行合并(如下图)。

image

transformData 方法就是遍历传入的 transformRequest 方法,将 dataheaders 作为 transformRequest 的入参,然后将返回结果复制给 config.data,作为最后请求要发送的 data 内容。

第 43 ~ 54 行 —— 合并请求 headers

config.headers = utils.merge(
  config.headers.common || {},
  config.headers[config.method] || {},
  config.headers
);

utils.forEach(
  ['delete', 'get', 'head', 'post', 'put', 'patch', 'common'],
  function cleanHeaderConfig(method) {
    delete config.headers[method];
  }
);

上面的代码主要做了两件事情:

  • 第一件事情就是将通用的 headerscommon headers)和对应方法的 headers 以及原 headers 做了一个合并;
  • 第二件事情就是在合并完成后,将多余的 headers 配置删除。

第 56 ~ 58 行 —— 发起真实请求

var adapter = config.adapter || defaults.adapter;

return adapter(config).then(function onAdapterResolution(response) {
  // ...
});

这里使用了配置的 adapter,这其实就是发起请求的方法。

image

比如两个默认的请求方法,在浏览器端运行时使用的是 XMLHttpRequest,在 Node 端运行时使用的是 http 模块。

知道这一项配置可以做什么呢?

你可以在这里传入一个自定义的请求方法,例如在客户端使用 fetch 封装,而不是 XMLHttpRequest

你也可以在这里传入一个你封装好的 mock 方法,返回的都是本地 json 数据,用于 mock 数据,这样你就不用额外搭建一个 mock 服务啦。

......

言归正传,我们还是来看看 axios 默认的两个 adapter 吧,本文会重点讲解客户端 adapter —— xhrAdapter

客户端 adapter —— xhrAdapter

我们按照惯例,对客户端 adapter —— xhrAdapter 逐行进行解析。

发起请求前的准备工作

image
行数 描述
16 ~ 18 收集请求数据信息(requestData)、请求头信息(requestHeaders)、返回体类型(responseType
19 ~ 28 cancelToken 做处理,在请求完成的时候取消这个订阅,释放内存;还有对 signal 的处理,这个 signal 在文档中已经看不到了,应该也是用于 abort 请求的。
30 ~ 32 对于 FormData 的请求移除 Content-Type 请求头,让浏览器自动设置请求头。

设置鉴权信息

image

首先在第 34 行,创建了一个 XMLHttpRequest 实例,用于后续的网络请求。

然后在第 37 ~ 41 行,设置了用于 HTTP basic authentication 鉴权的信息,从这一段我们可以学到简单的 HTTP basic authentication 鉴权知识。

首先对 password 进行 encodeURLComponent 转义编码,然后再将用户名与密码按照规则拼接后,使用了 btoa用户名与密码 转成了 base64 编码。

如果以后你要自己做这类事情的话,可以再翻到这一章节找到这部分的代码内容,抄一遍。

拼接请求 url

image

首先是用 buildFullPath 方法拼接了完整的请求 url。(如下图)

image

可以看到,该方法对绝对路径的 urlisAbsoluteURL()) 是不会拼接 baseURL 的。

然后,axios 还用 buildURL 方法将 params 参数拼接到了 url 中 —— 也就是我们常说的 query 参数。(如下)

function buildURL(url, params, paramsSerializer) {
  /*eslint no-param-reassign:0*/
  if (!params) {
    return url;
  }

  var serializedParams;
  if (paramsSerializer) {
    serializedParams = paramsSerializer(params);
  } else if (utils.isURLSearchParams(params)) {
    serializedParams = params.toString();
  } else {
    // ...

    serializedParams = parts.join('&');
  }

  if (serializedParams) {
    // ...
    // 在这里,将处理后的参数作为 query 查询参数拼接到 url 中
    url += (url.indexOf('?') === -1 ? '?' : '&') + serializedParams;
  }

  return url;
};

这也是为什么使用 axios 时,GET 方法的参数要设置在 params 字段中。

然后,使用 request.open 方法初始化了一个请求。

响应回调函数

接下来就是比较核心的响应回调函数了(如下图)

image
行数 描述
54 获取所有响应头
55 获取响应内容
57 ~ 64 设置 promise resolve 内容,就是你经常 console.log 出来的那些东西,你应该很眼熟

设置其他回调函数

后面基本上都是设置 XMLHttpRequest 对象的一些回调函数了。(如下图)

image

比较晚入行接触前端的,可能对 XMLHttpRequest 实例这些事件所做的事情不太清楚,可以参考一下 XMLHttpRequest 文档

最后,发送这个请求。(如下)

request.send(requestData);

回到 dispatchRequest

从上面可以看出,最后 dispatchRequest 调用 adapter 后,拿到了下面这些数据。

{
  data: responseData,
  status: request.status,
  statusText: request.statusText,
  headers: responseHeaders,
  config: config,
  request: request
};

然后我们来看看 dispatchRequest 内部是如何处理这一段数据的吧。(如下图)

image
行数 描述
59/72 处理被 CancelToken 取消的请求,如果请求已取消则不继续向下执行
62~67 将响应结果通过 transformResponse 进行转换,得到处理后的响应数据
69 将响应结果返回

这样一来,整个 axios 的请求流程就梳理清晰了,我们画一张流程图来梳理一下。(如下图)

image

这里对 Node 端的 adapter 就不进行展开讲解了,和客户端的差异主要在于下面几点:

  1. 使用了 Nodehttp 模块发起请求。
  2. 可以通过 proxy 设置代理服务器,请求将会发送到代理服务器。

小结

好了,我们对 axios 源码的解读就到这里为止了。

可以看出,axios 虽然是目前最流行的、比较强大的网络请求框架,但是源码看起来还是比较清爽易读的,建议大家可以自己按照文章的思路去看看。

下一章,我们会实现一个简易的 axios 框架,包含 axios 的一些核心功能,将 axios 源码解读系列收官。

最后一件事

如果您已经看到这里了,希望您还是点个赞再走吧~

您的点赞是对作者的最大鼓励,也可以让更多人看到本篇文章!

如果觉得本文对您有帮助,请帮忙在 github 上点亮 star 鼓励一下吧!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容