предисловие
Эта статья должнаjs
,es6
,webpack
,网络请求
Базовые знания и т. д. имеют базовое понимание
Полагатьaxios
Все использовали это или что-то网络请求
Соответствующие библиотеки, чтоajax
,fly.js
Подождите, подождите, я использовал только семь или восемь библиотек запросов, и все они похожи
Эта статья не предназначена для полной и дословной реализацииaxios
Все функции бессмысленны, но реализованы они будут по-разному, в основном для того, чтобы прочувствовать процесс и фреймворк, и то, как легко можно расширять проект, легко ли его тестировать, насколько читабельно и т.д.
Не говори глупостей, давай сделаем это~
Построить проект
Старое правило заключается в том, чтобы сначала создать пустой каталог, а затем открыть командную строку для выполнения
yarn init -y
или
cnpm init -y
webpack
затем импортироватьwebpack
, хотя этот раздел не посвященwebpack
, позвольте мне упомянуть немного здесь,webpack
иwebpack-cli
Не только в проекте скачать, но и глобально, т.е.yarn global add webpack webpack-cli
Установить зависимости
Для выполнения команд эти пакеты в основном нужны для компиляции и отладки.babel
помощьпопробуйСовместимость с браузерами, в конце концов, мы должны писать код, полныйes6
yarn add webpack webpack-cli webpack-dev-server babel-loader @babel/core @babel/preset-env
настроить веб-пакет
Далее создайте его в корневом каталогеwebpack.config.js
настроитьwebpack
, а затем построить еще одинsrc
директория для хранения кода нашей библиотеки, текущая директория будет выглядеть так
Просто сначала настройте его, а если возникнет необходимость добавить его позже, код будет добавлен прямо сюда.
~ webpack.config.js
const path = require('path');
module.exports = function() {
const dev = true;
return {
mode: dev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: dev ? 'axios.js' : 'axios.min.js',
sourceMapFilename: dev ? 'axios.map' : 'axios.min.map',
libraryTarget: 'umd',
},
devtool: 'source-map',
};
};
В настоящее времяsrc
Внутри постройтеindex.js
, а затем просто напишите что-то вроде этого
Затем терминал выполняетwebpack
Заказ
Конечно, сейчас он должен быть несовместим, иначе нам не придется загружать его в начале.babel
Теперь мы можем попробовать, как я сейчасindex.js
добавить предложение
Затем, после компиляции, вы можете видеть, что результат все ещеlet
, что точно не работает
Итак, следующий шаг — настроитьbabel
, тут нечего сказать, тут код прямо ставится, тут и говорить нечего
const path = require('path');
module.exports = function() {
const dev = true;
return {
mode: dev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: dev ? 'axios.js' : 'axios.min.js',
sourceMapFilename: dev ? 'axios.map' : 'axios.min.map',
libraryTarget: 'umd',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/i,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
};
};
Тогда вам точно не захочется вручную переходить к каждой модификацииwebpack
момент, не так ли? Пучокwebpack-dev-server
принести
~ webpack.config.js
const path = require('path');
module.exports = function() {
const dev = true;
return {
mode: dev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: dev ? 'axios.js' : 'axios.min.js',
sourceMapFilename: dev ? 'axios.map' : 'axios.min.map',
libraryTarget: 'umd',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/i,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
devServer: {
port: 8000,
open: true,
},
};
};
В это время запустите прямо в терминалеwebpack-dev-server
На самом деле он автоматически найдет глобальный модуль, что нехорошо, т.к. . . Знаешь
непосредственныйpackage.json
добавить команду
~ package.json
{
"name": "axios",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "webpack-dev-server"
},
"dependencies": {
"@babel/core": "^7.7.7",
"@babel/preset-env": "^7.7.7",
"babel-loader": "^8.0.6",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1"
}
}
потомyarn start
Появитсяhtml
Конечно, по умолчанию нужно найти кореньindex.html
, у нас его нет, поэтому создайте его под корнем, а затем введите нашaxios.js
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>axios</title>
</head>
<body>
<script src="/axios.js"></script>
</body>
</html>
Обновите страницу и вы увидитеsrc/index.js
внутреннийalert
вступает в силу
иwebpack-dev-server
Также возможно, если вы измените код, страница автоматически обновится
Тогда давайте сопоставимbuild
Здесь не так много ерунды, сразу переходим к коду
~ package.json
{
"name": "axios",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "webpack-dev-server --env.dev",
"build": "webpack --env.prod"
},
"dependencies": {
"@babel/core": "^7.7.7",
"@babel/preset-env": "^7.7.7",
"babel-loader": "^8.0.6",
"webpack": "^4.41.5",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.10.1"
}
}
~ webpack.config.json
const path = require('path');
module.exports = function(env={}) {
const dev = env.dev;
return {
mode: dev ? 'development' : 'production',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: dev ? 'axios.js' : 'axios.min.js',
sourceMapFilename: dev ? 'axios.map' : 'axios.min.map',
libraryTarget: 'umd',
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.js$/i,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
],
},
devServer: {
port: 8000,
open: true,
},
};
};
Видно, что все в порядке~
Хорошо, так вот я былwebpack
Связанные с этим дела почти закончены, и тогда мы начнем заниматься~
Код проекта Axios
Сначала построимcommon.js
, используемый для размещения общедоступных методов, сначала напишите утверждение
~ /src/common.js
export function assert(exp, msg = 'assert faild') {
if (!exp) {
throw new Error(msg);
}
}
Затем создайте еще один файл (личная привычка)/src/axios
Здесь размещены основные файлы
Тогда давайте посмотримaxios
Как его использовать, можно ли его использовать напрямую?axios({...})
илиaxios.get
и т.д
существуетindex.js
Введите непосредственно результат, напишите ожидаемое использование, а затем дополните внутреннее, как написать
~ index.js
import axios from './axios';
console.log(axios);
axios({ url: '1.txt', method: 'post' });
axios.get('1.txt', { headers: { aaa: 123 } });
axios.post(
'1.txt',
{ data: 123 },
{
headers: {
bbb: 123,
},
},
);
В это время мы должны подумать об этом. Мы можем напрямую писать функции. Это не проблема, но это слишком разбросано. Мне лично это не нравится, но это тоже возможно, поэтому я напишу это как класс здесь. Поскольку он изменен на класс, он будет выводиться. должен быть один实例
, поскольку это экземпляр, то его нельзя запускать напрямую, как функцию ()
Правильно, мы можем использовать нашproxy
в настоящее время,js
изclass
внутреннийconstructor
даreturn
Если вы не знакомы с этой вещью, я предлагаю вам сначала пойти и увидеть ее.js
изclass
, я не буду здесь вдаваться в подробности, а в основном объясню идею
Проще говоря, мы можемreturn
Одинproxy
объект для проксирования результатов, которые мы возвращаем, чтобы мы могли напрямую использоватьclass
Его можно записать так же, как функцию непосредственно при использовании.()
перечислить
Затем распечатайте его
~
Глядя на страницуconsole
, тогда вы можете увидетьaxios
только одинproxy
объект, как это
В это время вы все еще можете увидеть ошибку, потому что сейчас мы возвращаемproxy
Объект, больше не класс экземпляра, нетget
Это также разумно
Некоторые могут задаться вопросом, почему этоproxy
Контролируемый объект должен контролироваться отдельноproxy
функция, прямой мониторингthis
Не правда ли, обратите внимание, это на самом деле невозможно, поймитеproxy
друзья должны знать,proxy
То, что вы используете для наблюдения за созданием, очень важно.Если вы следите за объектом, вы все равно не можете вызвать его напрямую.Если вы хотите вызвать его напрямую, как функцию, то вы также должны следить за функцией.
нравится
Тогда давайте решим этоget
Проблема в том, что функция не может быть найдена, приходите кproxy
Добавить метод, очень простой, вы можете датьproxy
добавить однуget
метод, кто-то приходит к нему, просто вернись и найди его из моего класса, разве это не конец, но обратите внимание на это немногоthis
, пишите прямоthis
это указывает на этоproxy
function request() {}
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
let axios = new Axios();
export default axios;
Посмотрите еще раз на этот раз, ошибки нет, иget
иpost
также можетconsole
публично заявить
В это время мы можем продолжать писать запросы данных. . . . . ? Далеко не достаточно
axios
В параметрах много разнообразия, хотим подытожить
axios('1.txt',{})
axios({
url: '1.txt',
method
})
axios.get('1.txt')
axios.get('1.txt',{})
axios.post....
Подождите, как можно единообразно обрабатывать такие сложные параметры с несколькими источниками?
Второйaxios
Параметры могут быть настроены очень глубоко, как глобально, так и индивидуально, перехватчики,transfrom
что, подождите, дефолты и т.д.
параметр
первыйdefault
, чтобы определить эти значения по умолчанию, вот немного об этомX-Request-By
Это неписаная спецификация, и это то, что готова сделать библиотека общих запросов, чтобы фон мог судить, исходит ли ваш запрос отajax
все ещеfrom
или браузерurl
function request() {}
const _default = {
method: 'get',
headers: {
common: {
'X-Request-By': 'XMLHttpRequest',
},
get: {},
post: {},
delete: {},
},
};
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
let axios = new Axios();
export default axios;
Конечно картинка здесь простая, просто напишите несколько параметров, при желании можно много чего добавить, напримерdata
Сначала достаточно значения по умолчанию и т. д., а затем, если его недостаточно
Теперь давайте подумаем об этомdefault
Кого добавить напрямуюaxios.default = _default
Ну, конечно, нет, потому что мыaxios
Это будет необходимо в концеaxios.create
Если экземпляров несколько, то в это время работать не будет, и они будут влиять друг на друга.prototype
не говоря уже о
На самом деле, это тоже очень просто, каждый раз, когда вы создаете его из_default
Просто сделайте новую копиюJSON.parse(JSON.stringify(_default))
Просто упакуйте его, что также является наиболее эффективным способом, а затем немного измените код.
function request() {}
const _default = {
method: 'get',
headers: {
common: {
'X-Request-By': 'XMLHttpRequest',
},
get: {},
post: {},
delete: {},
},
};
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
Axios.create = Axios.prototype.create = function() {
let axios = new Axios();
axios.default = JSON.parse(JSON.stringify(_default));
return axios;
};
export default Axios.create();
Вот дополнение и к прототипу и к экземпляруcreate
метод, потому что мы можем напрямую использоватьaxios.create()
Также можно использовать напрямуюaxios()
, Простое добавление статических методов или методов экземпляра не может удовлетворить наши потребности.
Теперь давайте поэкспериментируем, сначалаconsole
немногоaxios.default
ты найдешь,undefined
,зачем это,явно сюда добавили
потому что на этот разaxios
не предмет, аproxy
, мы не далиproxy
добавлятьset
Верен ли метод? Я ничего не могу добавить. Давайте сейчас изменим код.
function request() {}
const _default = {
method: 'get',
baseUrl: "",
headers: {
common: {
'X-Request-By': 'XMLHttpRequest',
},
get: {},
post: {},
delete: {},
},
};
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
Axios.create = Axios.prototype.create = function() {
let axios = new Axios();
axios.default = JSON.parse(JSON.stringify(_default));
return axios;
};
export default Axios.create();
Затем снова посмотрите в браузере, вы найдете этоdefault
Там есть
и мы приходимcreate
дваaxios
, попробуйте изменить параметры
Два параметра экземпляра также не имеют значения, что также хорошо для начала.n
шаг, теперь мы закончилиaxios
четверть
Теперь у нас нет эффекта между экземплярами, но когда мы меняем параметры, это не только напрямуюaxios.default.xxx
Итак, измените, у нас также должны быть параметры, подобные этому
Здесь мы можем напрямую изменитьaxios.create
метод
~ axios.js
...
Axios.create = Axios.prototype.create = function(options={}) {
let axios = new Axios();
axios.default = {
...JSON.parse(JSON.stringify(_default)),
...options
};
return axios;
};
...
Просто разверните и замените его, не так ли?
Предположим, мы передаем объект напрямую, который имеетheaders
Если да, вы просто даете нам параметры по умолчанию напрямую?header
Приходится заменять целиком, то это не очень хорошо.Конечно,это зависит и от наших потребностей в собственной библиотеке.Если мы просто хотим это сделать,то в этом нет ничего плохого.Проблема в следующем
Тогда в это время мы можем использовать небольшую рекурсию, чтобы получить его
~ axios.js
...
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
function merge(dest, src) {
for (let name in src) {
if (typeof src[name] == 'object') {
if (!dest[name]) {
dest[name] = {};
}
merge(dest[name], src[name]);
} else {
dest[name] = src[name];
}
}
}
merge(res, options);
axios.default = res;
return axios;
};
...
Посмотри сейчас, все будет хорошо
Сортировка и разделение кода
Далее не будем спешить писать параметры запроса, немного спланируем и организуем код, ведь он все в одном файле, и его нельзя поддерживать в дальнейшем.
Нынешний сплит можно разделить на несколько пунктов
-
default
Можно ли использовать отдельный файл для установки - это
merge
Функция определенно общедоступна и может быть размещена в нашемcommon.js
внутри - это
request
также должны быть помещены в отдельныйjs
определять
Не говорите ерунды, сразу переходите к коду
~ request.js
export default function request() {
}
~ default.js
export default {
method: 'get',
baseUrl: '',
headers: {
common: {
'X-Request-By': 'XMLHttpRequest',
},
get: {},
post: {},
delete: {},
},
};
~ common.js
export function assert(exp, msg = 'assert faild') {
if (!exp) {
throw new Error(msg);
}
}
export function merge(dest, src) {
for (let name in src) {
if (typeof src[name] == 'object') {
if (!dest[name]) {
dest[name] = {};
}
merge(dest[name], src[name]);
} else {
dest[name] = src[name];
}
}
}
~ axios.js
import _default from './default';
import { merge } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
get() {
console.log('get');
}
post() {
console.log('post');
}
delete() {}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
Теперь он кажется намного чище, верно?
Обработка параметров запроса
Прежде чем писать, давайте посмотримaxios
Какие поддерживаются способы записи, а потом рассмотрим, как писать
В дополнение к общемуaxios({...})
Похожи ли эти три метода?axios
В ней слишком много всего, поэтому я просто реализую здесь эти три.Главная проблема в том, чтобы объяснить проблему.Если вам интересно, вы можете добавить ее сами.Это не более чем физический труд.
Конечно, вы можете видетьaxios
Есть еще довольно много параметров, в этот раз мы должны работать с ними напрямую, независимо от того, какие параметры будут переданы, мы вернемaxios({})
Это окончательное унифицированное лечение, разве это не удобно?
Здесь мы непосредственно судим о первых двух случаях
Вы найдете первые два случая в дополнение к этомуmethod
одинаковы, то мы можем извлечь метод, чтобы работать с ним единообразно
~ axios.js
import _default from './default';
import { merge } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
_preprocessArgs(method, ...args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
} else {
return undefined;
}
return options;
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
Тогда в это время, с точки зрения инкапсуляции библиотеки, нам обязательно нужно выполнить различные проверки параметров, типов и т. д. Если это не так, выдайте ему серьезную ошибку, чтобы помочь пользователям отлаживать
мы были раньшеcommon.js
написано наassert
Вот когда я использовал его
...
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
// ...
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
}
}
}
...
Правила здесь соответствуют написанным вышеaxios
Вообще говоря, метод использования аналогичен, после проверки этих параметров мы можем написать конкретную персонализированную обработку.
Кстати, это место конечно можно переиспользовать, но не обязательно.После этого не сильно уменьшится код, и получится грязно.Это зависит от человека.Не нравится-ты можете изменить его самостоятельно.
Тогда давай разберемся с этимoptions
,иconsole
немного
~ axios.js
import _default from './default';
import { merge, assert } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
console.log(fn, thisArg, args);
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
} else {
return undefined;
}
console.log(options);
return options;
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
console.log(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
console.log(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
console.log(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
console.log(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
Теперь давайте проверим
~ index.js
import Axios from './axios';
Axios.get('1.json');
Axios.get('1.json', { headers: { a: 12 } });
Axios.post('1.php');
Axios.post('1.php', { a: 12, b: 5 });
Axios.post('1.php', [12, 5, 6]);
let form = new FormData();
Axios.post('1.txt', form);
Axios.post('1.txt', 'dw1ewdq');
Axios.post('1.json', form, { headers: { a: 213, b: 132 } });
Axios.delete('1.json');
Axios.delete('1.json', { parmas: { id: 1 } });
Вы можете видеть это сейчас, верно?
Тогда что. . . Не забыли, нам еще нужно разобраться с прямымиapply
случае, то есть непосредственноAxios()
когда так зовут
Ничего лишнего, переходите сразу к коду, следуйтеget
На самом деле почти
~ axios.js
import _default from './default';
import { merge, assert } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
console.log(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
} else {
return undefined;
}
console.log(options);
return options;
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
console.log(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
console.log(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
console.log(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
console.log(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
тогда проверь это
нет проблем, конечно, почемуmethod
даundefined
, потому что это время еще не пришло к намdefault
Что ж, здесь мы определяем значение запроса по умолчанию, так что вот прямоеundefined
Хорошо, тогда мы должны положить немногоoptions
все иdefaulft
Готово, бросай намrequest
функция для запроса
И этот метод обязательно нужен для всех запросов, так что давайте напишем публичный метод
этоrequest
Метод в основном делает четыре вещи
- Объединить с this.default
- Проверьте правильность параметров
- запрос на слияние baseUrl
- Официальный запрос вызова (варианты)
import _default from './default';
import { merge, assert } from './common';
import request from './request';
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
_this.request(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
this.request(options);
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
this.request(options);
} else {
return undefined;
}
return options;
}
request(options) {
console.log(options, 'request');
// 1. 跟this.default进行合并
// 2. 检测参数是否正确
// 3. baseUrl 合并请求
// 4. 正式调用request(options)
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
this.request(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
this.request(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
this.request(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
this.request(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
Это слияние очень простое, мы писали ранееmerge
Функция снова пригодится, модифицируйте код
...
request(options) {
console.log(options);
// 1. 跟this.default进行合并
merge(options, this.default);
console.log(options);
// 2. 检测参数是否正确
// 3. baseUrl 合并请求
// 4. 正式调用request(options)
}
...
В это время видно, что данные до и после слияния уже доступны, но в это время нашиheader
Это не должно быть все из них, это должно быть основано наmethod
Как поставить соответствующийheader
иcommon
сливаться
request(options) {
// 1. 跟this.default进行合并
let _headers = this.default.headers;
delete this.default.headers;
merge(options, this.default);
this.default.headers = _headers;
//合并头
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
console.log(headers);
console.log(options);
// 2. 检测参数是否正确
// 3. baseUrl 合并请求
// 4. 正式调用request(options)
}
Здесь немного грязно, так что давайте сначала посмотрим
Наша цель - сделатьheader
Слияние, но будет небольшая проблема со слиянием, прежде чем мы были вdefault
определено вcommon
,get
... также будет скопировано, если мы используемif
судитьoptions.header.common == this.default.headers.common
потомdelete
Если это так, вы обнаружите, что в настоящее время это невозможно, потому что мы также знаем, что если вы прямо пишете два суждения об объектах, это эквивалентно прямомуnew
два объекта, то суждение определенно не равно в это время, так когда же мы его скопировали?
Просто когда мы инкапсулируемmerge
, и во многие другие места перенесли эту штуку
Затем мы должны выяснить, когда эта вещь отличается, на самом деле она наша.request
первый раз в функцииmerge
когда
Так что мы играем здесь небольшую хитрость, потому чтоcommon
Эти вещи были сделаны вручную ниже, поэтому ему не нужно копировать сюда, поэтому сначалаdelete
немного
Пусть не влезет раньше,delete
После этого я заберу его обратно, и два конца не будут задерживаться. Это действительно хорошо~
Наконец, мы положилиheaders
присвоить нашемуoptions.headers
request(options) {
// 1. 合并头
let _headers = this.default.headers;
delete this.default.headers;
merge(options, this.default);
this.default.headers = _headers;
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
options.headers = headers;
console.log(options);
// 3. baseUrl 合并请求
// 4. 正式调用request(options)
}
~ index.js
import Axios from './axios';
Axios('1.php');
Axios({
url: '2.php',
params: { a: 12, b: 3 },
headers: {
a: 12,
},
});
проверить результаты
Как видишь, все в порядке~
Тогда давайте посмотрим на второй шаг, На самом деле, мы можем написать много вещей, которые стоит проверить для этой проверки, но здесь объясняется только смысл, даже если вы напишете несколько, вы можете сделать больше, если вам интересно.
...
assert(options.method, 'no method');
assert(typeof options.method == 'string', 'method must be string');
assert(options.url, 'no url');
assert(typeof options.url == 'string', 'url must be string');
...
Третий шаг непосредственно в коде
~ axios.js
options.url=options.baseUrl+options.url;
delete options.baseUrl;
~ common.js
export function assert(exp, msg = 'assert faild') {
if (!exp) {
throw new Error(msg);
}
}
export function merge(dest, src) {
for (let name in src) {
if (typeof src[name] == 'object') {
if (!dest[name]) {
dest[name] = {};
}
merge(dest[name], src[name]);
} else {
if (dest[name] === undefined) {
dest[name] = src[name];
}
}
}
}
~ index.js
import Axios from './axios';
Axios('1.php', {
baseUrl: 'http://www.baidu.com/',
headers: {
a: 12,
},
});
Ï
В это время протестируйте его снова, вы увидите, что проблем нет.
Вот почему вам нужно изменить его
merge
, добавил суждение, потому что мы заменили его непосредственно перед тем, заменили мы его или нет, это определенно не хорошо, если мы не добавим его, нашbaseUrl
Выполнено
Конечно, есть одна маленькая вещь, с которой нам нужно разобраться, если человек, который использует вашу библиотеку, имеет больной разум (конечно, можно игнорировать больной разум), когда он пишет путь, он пишет его так:
Вы не можете сделать это снова, это очень просто,NodeJS
существует одинurl
пакет, вы можете использовать его напрямую,webpack
поможет вам упаковать его, но есть одно замечание,webpack
Не все можно упаковать, напримерfs
модули и даже некоторые низкоуровневые функцииc
иc++
Написанный системный пакет работать точно не будет, ноurl
нет проблем
~ axios.js
import _default from './default';
import { merge, assert } from './common';
import request from './request';
const urlLib = require('url');
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
_this.request(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
this.request(options);
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
this.request(options);
} else {
return undefined;
}
return options;
}
request(options) {
// 1. 合并头
let _headers = this.default.headers;
delete this.default.headers;
merge(options, this.default);
this.default.headers = _headers;
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
options.headers = headers;
console.log(options);
// 2. 检测参数是否正确
assert(options.method, 'no method');
assert(typeof options.method == 'string', 'method must be string');
assert(options.url, 'no url');
assert(typeof options.url == 'string', 'url must be string');
// 3. baseUrl 合并请求
options.url = urlLib.resolve(options.baseUrl, options.url);
delete options.baseUrl;
// 4. 正式调用request(options)
request(options);
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
this.request(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
this.request(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
this.request(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
this.request(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
Проверьте это снова
нет проблем
проблема слияния
На самом деле мыmerge
По-прежнему существует большая проблема, потому что функция, которую мы изначально хотели, отличается от нашей текущей функции.
Теперь мы вынуждены написатьif
, поменяли на проверку на утечки и заполнение вакансий, то по факту порядок вещей с приоритетом должен быть обратным
Какова наша первоначальная потребность, это сделать этоdest
Приоритет самый низкий и может быть переопределен другими, но сейчас так написаноif
После этого он становится его высшим приоритетом, то это неправильно, а удалить нельзя.После удаления у слияния опять будут проблемы.
this.default
Он изменился. На данный момент вам нужно сделать копию. Давайте напишем публичный метод и поместим его вcommon.js
внутри
~ common.js
...
export function clone(obj) {
return JSON.parse(JSON.stringify(obj));
}
И давайте немного изменим порядок, а затем клонируем данные
Давайте проверим это сейчас
выяснит лиheader
Эти вещи здесь вернулись, и причина очень проста, потому что мыdefault
даватьclone
вниз, так что давайте положитьdelete
Поднимите этот кусок вверх
теперь все будет хорошо
request
В это время мы должны написать четвертый шаг.
напрямуюoptions
намrequest
Это можно сделать в функции, и все мелочи решаются ею.
затем измените егоrequest.js
~ request.js
export default function request(options) {
console.log(options);
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, true);
for (let name in options.headers) {
xhr.setRequestHeader(name, options.headers[name]);
}
xhr.send(options.data);
}
Напишите пока простой запрос, а потом давайте проверим, можно ли его отправить
Сначала постройтеtxt
, нам удобно тестить, вставлюdata
каталог, как это
затем измените егоindex.js
~ index.js
import Axios from './axios';
Axios('/data/1.txt', {
headers: {
a: 12,
},
});
Теперь мы можем видеть, что,header
добавляется, и то, что возвращается, является правильным
Конечно, это еще не конец, это также вопрос, чтобы пользователи не создавали проблем
Если пользователь дает вамheader
Это как-то так, то это не очень хорошо, так что лучше дайте ему код
~ request.js
export default function request(options) {
console.log(options);
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, true);
for (let name in options.headers) {
xhr.setRequestHeader(
encodeURIComponent(name),
encodeURIComponent(options.headers[name]),
);
}
xhr.send(options.data);
}
Это не проблема.В случае возникновения проблемы в фоновом режиме, как только вы столкнетесь с двоеточием, вы можете решить эту проблему и избежать ее.
Затем, когда мы его используем, нам определенно понадобится еще один.async
иawait
поэтому нам нужно использоватьPromise
упаковать
~ axios.js
export default function request(options) {
console.log(options);
let xhr = new XMLHttpRequest();
xhr.open(options.method, options.url, true);
for (let name in options.headers) {
xhr.setRequestHeader(
encodeURIComponent(name),
encodeURIComponent(options.headers[name]),
);
}
xhr.send(options.data);
return new Promise((resolve, reject) => {
xhr.onreadystatechange = function() {
if (xhr.readyState == 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(xhr);
} else {
reject(xhr);
}
}
};
});
}
И в это время у нас еще много-много вопросов
- 304 на самом деле является успешным, поэтому инкапсулировать его неправильно, и у пользователя могут быть какие-то нестандартные
code
, как это настроить - наш текущий
webpack
только совместимыеes6
,async
иawait
не совместимо, как это сопоставить
Давайте сначала решимwebpack
Проблема, это на самом деле очень просто, нам нужно нажать другой пакетyarn add @babel/polyfill
затем откройтеwebpack.config.js
немного отредактироватьentry
~ webpack.config.js
...
entry: ['@babel/polyfill','./src/index.js'],
...
Обратите внимание, что этот порядок нельзя изменить
Это совместимо, а затем давайте изменим его сноваindex.js
import Axios from './axios';
(async () => {
let res = await Axios('/data/1.txt', {
headers: {
a: 12,
b: '321fho:fdsf vfds; : ',
},
});
console.log(res);
})();
Видно, что результатundefined
, это потому, что мы вообще не вернули результат обработки
Измените это сейчасaxios.js
import _default from './default';
import { merge, assert, clone } from './common';
import request from './request';
const urlLib = require('url');
class Axios {
constructor() {
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
return _this.request(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
this.request(options);
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
this.request(options);
} else {
return undefined;
}
return options;
}
request(options) {
// 1. 合并头
let _headers = this.default.headers;
delete this.default.headers;
let result = clone(this.default);
merge(result, this.default);
merge(result, options);
this.default.headers = _headers;
options = result;
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
options.headers = headers;
// 2. 检测参数是否正确
assert(options.method, 'no method');
assert(typeof options.method == 'string', 'method must be string');
assert(options.url, 'no url');
assert(typeof options.url == 'string', 'url must be string');
// 3. baseUrl 合并请求
options.url = urlLib.resolve(options.baseUrl, options.url);
delete options.baseUrl;
// 4. 正式调用request(options)
return request(options);
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
return this.request(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
return this.request(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
return this.request(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
return this.request(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = { ...JSON.parse(JSON.stringify(_default)) };
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
На этот раз давайте посмотрим на результаты, все ли в порядке? Конечно, мы не можем просто напрямую преобразовать исходныйxml
Объект возвращается, и нам также нужно выполнить различную обработку возвращенных данных.
Обработка данных
Сделаем простое изменениеaxios.js
внизrequest
вернуть другойpromise
, вы можете увидеть результат в это время, нет никаких проблем
Но давайте положим все этоaxios.js
Внутри слишком грязно, так что давайте уберем и его отдельно
Создайте два файла один/src/response.js
один/src/error.js
то здесьaxios.js
Представьте его и передайте им отдельно при работе с ним.
потомresponse.js
Просто верните значение напрямую
Но этоheaders
Немного особенный, вам нужно настроить метод отдельноxhr.getAllResponseHeaders()
, но это возвращает оригиналxhr
голову, это определенно не сработает, так что нам нужно ее отрезать
~ ответ.js
export default function(xhr) {
let arr = xhr.getAllResponseHeaders().split('\r\n');
let headers = {};
arr.forEach(str => {
if (!str) return;
let [name, val] = str.split(': ');
headers[name] = val;
});
return {
ok: true,
status: xhr.status,
statusText: xhr.statusText,
data: xhr.response,
headers,
xhr,
};
}
это нормально
transformRequest
&& transformResponse
Конечно, это еще не конец, потому что наша нынешняяdata
Обработки пока нет, поэтому это должна быть строка, и пользователи могут настраивать этот метод обработки, знакомый сaxios
друзья должны знать,axios
имеютtransformRequest
иtransformResponse
метод
В это время давайте сначала изменим егоaxios.js
внутреннийrequest
метод
Теперь нам нужно обработать запрос между шагами 3 и 4.
Сначала распечатайте параметры, а затем изменитеindex.js
контрольная работаdemo
Для удобства тестирования я положил1.txt
изменить на1.json
Хорошо, давай разберемся с этим позжеjson
Данные хороши, чтобы увидеть эффект
Видно, что этот параметр можно получить, тогда следующий шаг относительно прост, приходим сразу
Теперь посмотрите на запрос, этоheaders
только что добавленное
Только немного здесь, почему я хочуdelete
падать, хотя и неdelete
Это не имеет значения, но я бы хотел, чтобы у меня было этоrequest
не сорить, поддерживайте чистоту, содержите это в чистоте
Что касается этого пользовательского возвращаемого результата, он проще?
Вы можете увидеть результаты в это время, я не передал егоtransformResponse
, результат такой
Вот и все
Конечно, теперь мы можем использовать его гибко, а не только в одиночку.json
В нем можно настраивать параметры, а также есть возможность единообразно обрабатывать глобальную конфигурацию, попробуем.
и между разными экземплярами можно
перехватчик
Перехватчики определенно необходимы в библиотеке запросов.На самом деле, мы написали эту библиотеку до сих пор, и на самом деле очень легко добавить одну из этих вещей.
~ index.js
import Axios from './axios';
Axios.interceptors.request.use(function(config) {
config.headers.interceptors = 'true';
return config;
});
(async () => {
let res = await Axios('/data/1.json', {
headers: {
a: 12,
b: '321fho:fdsf vfds; : ',
},
});
console.log(res);
})();
затем создайте новыйinterceptor.js
~interceptor.js
class Interceptor {
constructor() {
this._list = [];
}
use(fn) {
this._list.push(fn);
}
list() {
return this._list;
}
}
export default Interceptor;
~ axios.js
import _default from './default';
import { merge, assert, clone } from './common';
import request from './request';
import createResponse from './response';
import createError from './error';
const urlLib = require('url');
import Interceptor from './interceptor';
class Axios {
constructor() {
this.interceptors = {
request: new Interceptor(),
response: new Interceptor(),
};
let _this = this;
return new Proxy(request, {
get(data, name) {
return _this[name];
},
set(data, name, val) {
_this[name] = val;
return true;
},
apply(fn, thisArg, args) {
let options = _this._preprocessArgs(undefined, args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
};
return _this.request(options);
} else {
assert(false, 'invaild args');
}
}
},
});
}
_preprocessArgs(method, args) {
let options;
if (args.length == 1 && typeof args[0] == 'string') {
options = { method, url: args[0] };
this.request(options);
} else if (args.length == 1 && args[0].constructor == Object) {
options = {
...args[0],
method,
};
this.request(options);
} else {
return undefined;
}
return options;
}
request(options) {
// 1. 合并头
let _headers = this.default.headers;
delete this.default.headers;
let result = clone(this.default);
merge(result, this.default);
merge(result, options);
this.default.headers = _headers;
options = result;
// this.default.headers.common -> this.default.headers.get -> options
let headers = {};
merge(headers, this.default.headers.common);
merge(headers, this.default.headers[options.method.toLowerCase()]);
merge(headers, options.headers);
options.headers = headers;
// 2. 检测参数是否正确
assert(options.method, 'no method');
assert(typeof options.method == 'string', 'method must be string');
assert(options.url, 'no url');
assert(typeof options.url == 'string', 'url must be string');
// 3. baseUrl 合并请求
options.url = urlLib.resolve(options.baseUrl, options.url);
delete options.baseUrl;
// 4. 变换一下请求
const { transformRequest, transformResponse } = options;
delete options.transformRequest;
delete options.transformResponse;
if (transformRequest) options = transformRequest(options);
let list = this.interceptors.request.list();
list.forEach(fn => {
options = fn(options);
});
// 5. 正式调用request(options)
return new Promise((resolve, reject) => {
return request(options).then(
xhr => {
let res = createResponse(xhr);
if (transformResponse) res = transformResponse(res);
let list = this.interceptors.response.list();
list.forEach(fn => {
res = fn(res);
});
resolve(res);
},
xhr => {
let err = createError(xhr);
reject(err);
},
);
});
}
get(...args) {
let options = this._preprocessArgs('get', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' &&
args[1] &&
args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
return this.request(options);
} else {
assert(false, 'invaild args');
}
}
}
post(...args) {
let options = this._preprocessArgs('post', args);
if (!options) {
if (args.length == 2) {
assert(typeof args[0] == 'string', 'args[0] must is string');
options = {
url: args[0],
data: args[1],
method: 'post',
};
return this.request(options);
} else if (args.length == 3) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[2] == 'object' &&
args[2] &&
args[2].constructor == Object,
'args[2] must is JSON',
);
options = {
...args[2],
url: args[0],
data: args[1],
method: 'post',
};
return this.request(options);
} else {
assert(false, 'invaild argments');
}
}
}
delete(...args) {
let options = this._preprocessArgs('delete', args);
if (!options) {
assert(typeof args[0] == 'string', 'args[0] must is string');
assert(
typeof args[1] == 'object' && args[1] && args[1].constructor == Object,
'args[1] must is JSON',
);
options = {
...args[1],
url: args[0],
method: 'get',
};
return this.request(options);
}
}
}
Axios.create = Axios.prototype.create = function(options = {}) {
let axios = new Axios();
let res = clone(_default);
merge(res, options);
axios.default = res;
return axios;
};
export default Axios.create();
Видно, что по сути это та же процедура, главное передать параметры и потом вызвать.
Тем не менее, есть две небольшие проблемы, которые необходимо решить
- Теперь мы даем пользователю много открытий, если он вернется
config
Если оно неправильное или не возвращено, мы должны вернуть ему сообщение об ошибке и проверить его снова.В это время все должны уметь думать об этом, верно?axios
Технического содержания, чтобы сделать функцию для проверки этих параметров, нет, поэтому я не буду здесь вдаваться в подробности, если вам интересно, вы можете попробовать. - То, что мы даем пользователю, это функция, которую мы используем
forEach
, это вызовет проблему, если пользователь даст вамasync
Функция , то работать не будет, надо еще добавитьasync
иawait
,ноasync
иawait
который возвращаетpromise
Это очень странно.Если вам интересно, вы можете попробовать сами, или оставить сообщение в области комментариев.
Теперь давайте попробуем эффект
Видно, что наш перехватчик тоже завершен.
Суммировать
Окончательный код этой статьи загруженgithub
, ссылка такаяGitHub.com/Mikey-9/Assi…
Тем не менее, это предложение, наша статья в основном не для достижения полной реализацииaxios
, но идея реализации такой библиотеки.Конечно, есть и много проблем.Вы можете оставить сообщение в области комментариев или добавить меняqq
или微信
общаться вместе
Это немного длинно, спасибо за просмотр
Thank You
qq:
WeChat: