axiosの内部構造を理解してadapterの仕組みを解明する
axiosのadapterを使う機会があり、仕組みが気になったのでメモしておく。
github.com
adapter
で検索をかけると、lib/core/dispatchRequest.js
の51行目の記述が目についた。
axios/dispatchRequest.js at 7821ed20892f478ca6aea929559bd02ffcc8b063 · axios/axios · GitHub
var adapter = config.adapter || defaults.adapter; return adapter(config).then(function onAdapterResolution(response) { ...
dispatchRequest.js
は名前からも、lib/core/Axios.js
で使われていることからも、実際にリクエストを送る部分であろう。
まずはdefaults.adapter
がなんなのかを調べると、lib/defaults.js
に以下の記述があった。
axios/defaults.js at 7821ed20892f478ca6aea929559bd02ffcc8b063 · axios/axios · GitHub
axios/defaults.js at 7821ed20892f478ca6aea929559bd02ffcc8b063 · axios/axios · GitHub
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; } ... var defaults = { adapter: getDefaultAdapter(), ....
typeof XMLHttpRequest
をchromeのコンソールで調べると以下のようになったので、adapter = require('./adapters/xhr');
の元を見にいった。
typeof XMLHttpRequest "function"
lib/adapters/xhr.js
では、XMLHttpRequestを使ってリクエストが送られていた。
axios/xhr.js at 7821ed20892f478ca6aea929559bd02ffcc8b063 · axios/axios · GitHub
axios/xhr.js at 7821ed20892f478ca6aea929559bd02ffcc8b063 · axios/axios · GitHub
axios/xhr.js at 7821ed20892f478ca6aea929559bd02ffcc8b063 · axios/axios · GitHub
var request = new XMLHttpRequest(); ... request.open(config.method.toUpperCase(), buildURL(fullPath, config.params, config.paramsSerializer), true); ... // Send the request request.send(requestData);
つまり、axiosをadapter
オプションを指定せずに使うと、内部的にはXMLHttpRequest
を使った通信が行われ、adapter
オプションを指定すると、通信そのものをラップできることが分かる。
オプションの反映はlib/core/mergeConfig.js
を使って行われていることが分かったが、深追いはせずテストコードを眺めるだけに留めた。
axios/mergeConfig.spec.js at main · axios/axios · GitHub
実際にadapter
オプションを書いて使ってみた。
この場合リクエストは発生せず、実装したPromiseが返っている。
const axios = require("axios"); const sampleAdapter = () => { return new Promise((resolve, reject) => { resolve({ data: "sample data" }); }); }; axios({ url: "https://example.com/", adapter: sampleAdapter, }).then((res) => console.log(res.data));
$ node index.js sample data
リクエストを送る部分はlib/core
配下にあるものだと思っていたので、adapter
オプションを指定しない場合にlib/adapters
配下のコードが使われているのが意外だった。
追記:
axiosにPR投げてみたらlib/adapters
配下のコードが使われているという理解はあっていた。
github.com