Представляем аксиомы
Я пользуюсь библиотекой axios, и, наслаждаясь удобством, которое она дает, я всегда чувствую, что мне немного жаль, что я не читал ее исходный код.Бывает, что в Интернете мало статей об исходном коде axios, поэтому я пишу эту статью.
axios — это изоморфная библиотека асинхронных запросов JavaScript, которую можно использовать как в браузере, так и в среде NodeJS.
Автор VueJS, You Da, также рекомендует этот инструмент.Помимо функции асинхронного запроса сетевых ресурсов, он также имеет следующие функции:
- Обеспечьте функцию прокси
- Предоставляет перехватчики (похожие на промежуточное ПО), которые могут регистрировать действия до отправки запроса и после получения ответа.
- Может получить прогресс загрузки и прогресс загрузки
- Предоставленная опция адаптера может имитировать данные ответа
- Пользовательский код ответа, вызывающий диапазон ошибок
- Предоставляет возможность отменить запрос
аксиомыАдрес GitHub.
Так как же это сделать?
Сначала позвольте мне рассказать о том, почему его можно использовать в браузере и среде NodeJS.
В AXIOS шаблон конструкции адаптера используется для отображения различий на платформе, чтобы пользователи могли использовать тот же набор API для инициирования HTTP-запросов на боковой стороне браузера и в среде Nodejs.
Адаптер в конфигурации по умолчанию AXIOS проходит черезgetDefaultAdapter()
метода, его логика такова:
function getDefaultAdapter() {
var adapter;
// Only Node.JS has a process variable that is of [[Class]] process
if (typeof process !== 'undefined' && Object.prototype.toString.call(process) === '[object process]') {
// For node use HTTP adapter
adapter = require('./adapters/http');
} else if (typeof XMLHttpRequest !== 'undefined') {
// For browsers use XHR adapter
adapter = require('./adapters/xhr');
}
return adapter;
}
Как показано в приведенном выше коде, исходя из характеристик работающей среды, для инициирования http-запросов выбираются разные API.
Следующие разделы описывают эти два документа — http и xhr.
http.js
config
Получите некоторые настраиваемые параметры от пользователя, включая заголовки запроса, параметры запроса и т. д., а затем используйте (http/https).request(options, callback) для внутреннего инициирования HTTP-запроса.
Загрузите исходный код, чтобы узнать, как интегрировать и обрабатывать входящие параметры.
xhr.js
Логика, аналогичная http, просто вызывает интерфейс XMLHTTPRequest WebAPI для инициации http-запроса.
Реализация перехватчика
axios предоставляет функцию перехватчика, который может обрабатывать входящий конфиг или другие операции до того, как запрос будет инициирован, а также может обрабатывать ответ после получения ответа.
Мы можем посмотреть на конструктор Axios, он очень прост:
function Axios(instanceConfig) {
this.defaults = instanceConfig;
this.interceptors = {
request: new InterceptorManager(),
response: new InterceptorManager()
};
}
Среди них InterceptorManager поддерживает массив для сбора функций перехватчика, включаяfulfilled
а такжеrejected
, соответствующие обратным вызовам onSuccess и onFail для Promise соответственно. Далее давайте посмотрим, как объединяются перехватчик и HTTP-запрос. Давайте посмотрим на метод запроса на прототипе Axios:
Axios.prototype.request = function request(config) {
/*eslint no-param-reassign:0*/
// Allow for axios('example/url'[, config]) a la fetch API
if (typeof config === 'string') {
config = arguments[1] || {};
config.url = arguments[0];
} else {
config = config || {};
}
config = mergeConfig(this.defaults, config);
config.method = config.method ? config.method.toLowerCase() : 'get';
// Hook up interceptors middleware
var chain = [dispatchRequest, undefined];
var promise = Promise.resolve(config);
this.interceptors.request.forEach(function unshiftRequestInterceptors(interceptor) {
chain.unshift(interceptor.fulfilled, interceptor.rejected);
});
this.interceptors.response.forEach(function pushResponseInterceptors(interceptor) {
chain.push(interceptor.fulfilled, interceptor.rejected);
});
while (chain.length) {
promise = promise.then(chain.shift(), chain.shift());
}
return promise;
};
Как видно из вышеизложенного, способ их объединения заключается в использовании Promise для объединения перехватчика и операции инициации http-запроса.interceptors.request
Он будет организован перед операцией инициации http-запроса.interceptors.response
Он будет организован после операции, которая инициирует http-запрос.
Прогресс загрузки и скачивания
axios предоставляет функцию наблюдения за ходом загрузки и выгрузки, но только в среде браузера, основной код выглядит следующим образом:
// 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.событие прогресса, обратный вызов процесса загрузки на самом деле является атрибутом загрузки объекта XMLHTTPRequest.событие прогресса.
Официальная документация указывает на то, что эта функция требует, чтобы разработчик вернуть объект и возвращает объект ответа на обещание в действительном обещании в:
// `adapter` allows custom handling of requests which makes testing easier.
// Return a promise and supply a valid response (see lib/adapters/README.md).
adapter: function (config) {
/* ... */
}
Мы можем найти реализацию этой функции в исходном коде:
var adapter = config.adapter || defaults.adapter;
return adapter(config).then(function onAdapterResolution(response) {
throwIfCancellationRequested(config);
// Transform response data
response.data = transformData(
response.data,
response.headers,
config.transformResponse
);
return response;
}, function onAdapterRejection(reason) {
if (!isCancel(reason)) {
throwIfCancellationRequested(config);
// Transform response data
if (reason && reason.response) {
reason.response.data = transformData(
reason.response.data,
reason.response.headers,
config.transformResponse
);
}
}
return Promise.reject(reason);
});
Как видно из вышеперечисленного, если мы используем Axios, чтобы сделать HTTP-запрос, если объект входящего конфигурации имеет атрибут адаптера, этот атрибут заменит адаптер по умолчанию (HTTP.REQUEST NODEJSS.REQUEST () или XMLHTTREQUEST), поэтому нам нужно Используйте его в обещании, возвращается в свойство адаптера конфигурации, и это обещание вернет действительный объект ответа.
Настройте диапазон кодов ответов, вызывающих ошибки
axios предоставляет функцию для настройки диапазона кодов ответа на ошибку, которые могут быть переданы черезconfig.validateStatus
настроить.
Диапазон по умолчанию составляет от 200 до 300:
validateStatus: function validateStatus(status) {
return status >= 200 && status < 300;
}
В исходном коде этот метод передается черезlib\core\settle.js
звонить:
module.exports = function settle(resolve, reject, response) {
var validateStatus = response.config.validateStatus;
if (!validateStatus || validateStatus(response.status)) {
resolve(response);
} else {
reject(createError(
'Request failed with status code ' + response.status,
response.config,
null,
response.request,
response
));
}
};
Как видно из вышеизложенного, входные параметры расчёта очень похожи на резолв и отклонение промиса.Далее посмотрим, где вызывается расчёт.
Конечно же, вlib\adapters\http.js
а такжеlib\adapters\xhr.js
В обоих видна фигура Сеттла.
Я не буду вдаваться в подробности. Я дам общее представление. После того, как axios использует Promise для инициации HTTP-запроса, он передаст разрешение и отклонение в функции, переданной в объекте Promise, для повторного выполнения, и пусть он решить, является ли состояние обещания onResolved или нет.
Возможность отменить заявку
В официальной документации axios указано, что axios предоставляет функцию отмены уже отправленных запросов.
The axios cancel token API is based on the withdrawn cancelable promises proposal.
В приведенной выше цитате говорится, что это было обещание, но с тех пор оно было отозвано.
Здесь автор хочет сказать, что, не полагаясь на это предложение, мы также можем написать простую функцию отмены запроса, если вы знакомы с замыканиями.
Идея такова: мы можем использовать метод закрытия, чтобы поддерживать состояние того, следует ли отменить запрос, а затем судить об этом состоянии при обработке обратного вызова onResolved промиса, Если состояние должно отменить запрос, мы можем отклонить результат , что примерно так:
function dispatchRequest(config) {
let hasCancled = false;
return Promise((resolve, reject) => {
if (hasCancled) {
reject({ hasCancled: true })
} else {
/** 处理正常响应 **/
}
})
.then(/** 其他业务操作 **/)
.catch(err => {
if (err.hasCancled) {
/** 处理请求被取消 */
}
})
}
Суммировать
Наконец, мы можем получить общее представление о силе axios: использование режима адаптера для маскировки различий между платформами, предоставление унифицированного API, использование связанного вызова Promise для обеспечения упорядоченности всего процесса запроса и расширения некоторых дополнительных возможностей. функции.
Библиотека axios — очень красивая третья библиотека, и стоит прочитать ее исходный код. Вы также получите много. Большое спасибо за то, что придерживаетесь этого.
В статье не только упоминаются, но и есть несколько интересных тем, которые стоит изучить, например:
- Как настроить Axios вверх по запросу запроса?
- Как добиться агента Axios