предисловие
axios
легкийHTTP客户端
, который основан наXMLHttpRequest
Сервис для выполнения HTTP-запросов, поддерживает богатую конфигурацию, поддерживаетPromise
, который поддерживает браузер иNode.js
конец. Начиная с Vue2.0, Ю Да (автор Vue Ю Юйси) объявил об отменеvue-resource
официальная рекомендация, которая, в свою очередь, рекомендуетaxios
. Сейчасaxios
Он стал первым выбором для большинства разработчиков Vue. (Если вы не знакомы сaxios
, допустимыйздесьПроверьте его API).
axios
API очень удобный, и вы можете легко использовать его прямо в своем проекте. Однако по мере увеличения масштаба проекта каждый раз, когда инициируется HTTP-запрос, должны выполняться такие операции, как установка периода ожидания, установка заголовка запроса, определение того, какой адрес запроса использовать в соответствии со средой проекта, обработка ошибок и т. д. быть написанным на месте Сумасшедший! Такое дублирование усилий не только тратит время, но и делает код избыточным и трудным для сопровождения.
Чтобы улучшить качество нашего кода, мы должны дважды инкапсулировать его в проекте.axios
повторное использование.
Итак, как инкапсулироватьaxios
Шерстяная ткань?
оригинальный внешний вид
Перед инкапсуляцией давайте посмотрим, как выглядит запрос axios в реальном проекте без инкапсуляции. Это выглядит так:
axios('http://localhost:3000/data', {
method: 'GET',
timeout: 1000,
withCredentials: true,
headers: {
'Content-Type': 'application/json',
Authorization: 'xxx',
},
transformRequest: [function (data, headers) {
return data;
}],
// 其他请求配置...
})
.then((data) => {
// todo: 真正业务逻辑代码
console.log(data);
}, (err) => {
if (err.response.status === 401) {
// handle authorization error
}
if (err.response.status === 403) {
// handle server forbidden error
}
// 其他错误处理.....
console.log(err);
});
Видно, что в этом коде логика кода страницы находится только в строке 15. Большой блок кода конфигурации запроса выше и большой блок кода обработки ошибок ответа ниже почти не имеют ничего общего с функциями страницы, и они находятся в каждый запрос.Содержание почти одинаковое, и даже некоторые части точно такие же. Представьте, каждый раз, когда отправляется запрос, какой будет грандиозный повод, когда будет написано десяток запросов?
Шаг упаковки
Суть инкапсуляции заключается в том, чтобы добавлять различные вещи за пределы инкапсулируемого контента, а затем представлять их пользователю как новое целое для достижения цели расширения и простоты использования.
упаковкаaxios
Нужно заранее настроить конфигурацию, разделяемую всеми HTTP-запросами на axios, зарезервировать нужные параметры и интерфейсы, а затем вернуть как новый axios.
Затем мы используем демонстрацию для реализации хорошо расширяемойaxios
упаковка.
Структура демонстрационного каталога выглядит следующим образом (сгенерирована Vue-cli 3.0):
|--public/
|--mock/
| |--db.json # 我新建的接口模拟数据
|--src/
| |--assets/
| |--components/
| |--router/
| |--store/
| |--views/
| |--Home.Vue
| |--App.vue
| |--main.js
| |--theme.styl
|--package.json
|...
цель пакета
Я хочу сделать запрос axios на домашней странице таким же простым, как вызов метода с несколькими параметрами, чтобы я мог сосредоточиться на бизнес-коде.
1. Упакуйте аксиомы в отдельный файл
- Создание файла Utils / http.js под SRC
cd src
mkdir utils
touch http.js
- Представлены аксиомы
// src/utils/http.js
import axios from 'axios';
- создать класс Вы также можете использовать функции для инкапсуляции, я просто думаю, что классы более семантичны.
//src/utils/http.js
//...
class NewAxios {
}
- Настройте разные адреса запросов для разных сред
согласно с
process.env.NODE_ENV
Настроить отличатьсяbaseURL
, чтобы проект мог автоматически переключать адрес узла запроса в разных средах, просто выполняя соответствующую команду упаковки.
// src/utils/http.js
//...
const getBaseUrl = (env) => {
let base = {
production: '/',
development: 'http://localhost:3000',
test: 'http://localhost:3001',
}[env];
if (!base) {
base = '/';
}
return base;
};
class NewAxios {
constructor() {
this.baseURL = getBaseUrl(process.env.NODE_ENV);
}
}
- Настройка тайм-аута Свойство Timeout, я обычно устанавливаю на 10 секунд.
// src/utils/http.js
//...
class NewAxios {
constructor() {
//...
this.timeout = 10000;
}
}
- Настройте, чтобы разрешить учетные данные Для свойства widthCredentials установлено значение true.
// src/utils/http.js
//...
class NewAxios {
constructor() {
//...
this.withCredentials = true;
}
}
- Создайте запрос метода для экземпляра этого класса
существует
request
В методе создается новый экземпляр axios, принимаются параметры конфигурации запроса, обрабатываются параметры, добавляется конфигурация и возвращается результат запроса (объект обещания) экземпляра axios. Вы также можете использовать экспортированный экземпляр axios по умолчанию, не создавая его, и поместить в него всю конфигурацию, но таким образом весь проект будет совместно использовать один экземпляр axios. Хотя для большинства проектов этого достаточно, структуры запросов и ответов разных сервисных адресов в некоторых проектах могут быть совершенно разными, в этом случае совместное использование экземпляра не поддерживается. Итак, чтобы инкапсулировать более общий и более гибкий, я буду использовать метод создания axios, чтобы каждый запрос был новым экземпляром axios.
// src/utils/http.js
//...
class NewAxios {
//...
request(options) {
// 每次请求都会创建新的axios实例。
const instance = axios.create();
const config = { // 将用户传过来的参数与公共配置合并。
...options,
baseURL: this.baseURL,
timeout: this.timeout,
withCredentials: this.withCredentials,
};
// 配置拦截器,支持根据不同url配置不同的拦截器。
this.setInterceptors(instance, options.url);
return instance(config); // 返回axios实例的执行结果
}
}
Поскольку содержимое конфигурации перехватчика больше, оно инкапсулировано во внутреннюю функцию.
- Настроить перехватчик запросов Здесь единообразно настраиваются все изменения, внесенные в параметры запроса перед отправкой запроса. Например, единообразно добавлять учетные данные токена, единообразно задавать язык, единообразно устанавливать тип контента, указывать формат данных и т. д. Не забудьте вернуть эту конфигурацию, когда закончите, иначе весь запрос не будет обработан. Я настрою токен здесь.
// src/utils/http.js
//...
class NewAxios {
//...
// 这里的url可供你针对需要特殊处理的接口路径设置不同拦截器。
setInterceptors = (instance, url) => {
instance.interceptors.request.use((config) => { // 请求拦截器
// 配置token
config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || '';
return config;
}, err => Promise.reject(err));
}
//...
}
- Настроить перехватчик ответа
по требованию
then
илиcatch
Перед обработкой данных ответа выполняется цикл предварительной обработки. Например, фильтрация данных ответа и многое другое здесь предназначено для выполнения унифицированной обработки ошибок для различных кодов ошибок ответа, а также обработки отключения сети и т. д. Я буду судить 403 и разъединение здесь.
// src/utils/http.js
//...
class NewAxios {
//...
setInterceptors = (instance, url) => {
//...
instance.interceptors.response.use((response) => { // 响应拦截器
// todo: 想根据业务需要,对响应结果预先处理的,都放在这里
console.log();
return response;
}, (err) => {
if (err.response) { // 响应错误码处理
switch (err.response.status) {
case '403':
// todo: handler server forbidden error
break;
// todo: handler other status code
default:
break;
}
return Promise.reject(err.response);
}
if (!window.navigator.online) { // 断网处理
// todo: jump to offline page
return -1;
}
return Promise.reject(err);
});
}
//...
}
Кроме того, в перехватчике также удобно размещать такие эффекты буферизации, как загрузка: отображать загрузку в перехватчике запросов, а убирать загрузку в перехватчике ответов. Таким образом, все запросы имеют единый эффект загрузки.
- Экспорт новых экземпляров по умолчанию
// src/utils/http.js
//...
export default new NewAxios();
Окончательный полный код выглядит следующим образом:
// src/utils/http.js
import axios from 'axios';
const getBaseUrl = (env) => {
let base = {
production: '/',
development: 'http://localhost:3000',
test: 'http://localhost:3001',
}[env];
if (!base) {
base = '/';
}
return base;
};
class NewAxios {
constructor() {
this.baseURL = getBaseUrl(process.env.NODE_ENV);
this.timeout = 10000;
this.withCredentials = true;
}
setInterceptors = (instance, url) => {
instance.interceptors.request.use((config) => {
// 在这里添加loading
// 配置token
config.headers.AuthorizationToken = localStorage.getItem('AuthorizationToken') || '';
return config;
}, err => Promise.reject(err));
instance.interceptors.response.use((response) => {
// 在这里移除loading
// todo: 想根据业务需要,对响应结果预先处理的,都放在这里
return response;
}, (err) => {
if (err.response) { // 响应错误码处理
switch (err.response.status) {
case '403':
// todo: handler server forbidden error
break;
// todo: handler other status code
default:
break;
}
return Promise.reject(err.response);
}
if (!window.navigator.online) { // 断网处理
// todo: jump to offline page
return -1;
}
return Promise.reject(err);
});
}
request(options) {
// 每次请求都会创建新的axios实例。
const instance = axios.create();
const config = { // 将用户传过来的参数与公共配置合并。
...options,
baseURL: this.baseURL,
timeout: this.timeout,
withCredentials: this.withCredentials,
};
// 配置拦截器,支持根据不同url配置不同的拦截器。
this.setInterceptors(instance, options.url);
return instance(config); // 返回axios实例的执行结果
}
}
export default new NewAxios();
Сейчасaxios
Упаковка готова на 80%. Нам все еще нужно объединить axios с интерфейсом и инкапсулировать еще один уровень, чтобы достичь цели инкапсуляции, которую я поставил в начале.
2. Используйте новый API-интерфейс axios.
- Создайте новый в каталоге src
api
папка. Все интерфейсы, связанные с HTTP-запросами, унифицированы и управляются в этом каталоге. - новый
home.js
. Нам нужно классифицировать интерфейсы по определенным правилам, а класс интерфейсов соответствует js-файлу. Эту категорию можно разделить по страницам, по модулям и так далее. Чтобы продемонстрировать более интуитивно, я разделю его здесь по страницам. На самом деле это зависит от ваших потребностей. - Используйте новые аксиомы для инкапсуляции API (исправьте значение URL-адреса, объедините параметры, переданные пользователем), а затем назовите и экспортируйте эти функции.
// src/api/home.js
import axios from '@/utils/http';
export const fetchData = options => axios.request({
...options,
url: '/data',
});
export default {};
- Создайте новый в каталоге API
index.js
, и экспортировать в этот файл интерфейсы других файлов.
// src/api/index.js
export * from './home';
Этот уровень инкапсуляции инкапсулирует наши новые аксиомы в более лаконичный и семантический метод интерфейса.
Теперь наша структура каталогов выглядит так:
|--public/
|--mock/
| |--db.json # 接口模拟数据
|--src/
| |--api/ # 所有的接口都集中在这个目录下
| |--home.js # Home页面里涉及到的接口封装在这里
| |--index.js # 项目中所有接口调用的入口
| |--assets/
| |--components/
| |--router/
| |--store/
| |--utils/
| |--http.js # axios封装在这里
| |--views/
| |--Home.Vue
| |--App.vue
| |--main.js
| |--theme.styl
|--package.json
|...
Используйте упакованные axios
Теперь, когда мы хотим отправлять HTTP-запросы, нам просто нужно ввестиapi
внизindex.js
Файлы могут вызывать любой интерфейс и использовать инкапсулированныйaxios
.
// src/views/Home.vue
<template>
<div class="home">
<h1>This is home page</h1>
</div>
</template>
<script>
// @ is an alias to /src
import { fetchData } from '@/api/index';
export default {
name: 'home',
mounted() {
fetchData() // axios请求在这里
.then((data) => {
console.log(data);
})
.catch((err) => {
console.log(err);
});
},
};
</script>
запросы axios инкапсулируются вfetchData
В функции запрос страницы не должен появлятьсяaxios API
, молча отправляя запрос и получая ответ, точно так же, как вызов простогоPromise
функционировать так же легко. А на странице вам нужно сосредоточиться только на обработке бизнес-функций, не отвлекаясь на другие вещи.
бегать
бегатьnpm run serve
запустить проект, выполнитьnpm run mock
Запустите фиктивный интерфейс службы.
Открой сейчасlocalhost:8080
Вы можете увидеть домашнюю страницу. Откройте консоль браузера, и вы увидите напечатанный результат ответа на запрос:
Простой и элегантный.
Суммировать
- Идея инкапсуляции является очень полезной идеей в интерфейсных технологиях. Простые аксио и интерфейсная инкапсуляция позволяют нам оценить его очарование.
- упаковка
axios
Не существует абсолютного стандарта, если ваш пакет может удовлетворить потребности вашего проекта и удобен в использовании, это хорошее пакетное решение. - BTW: Вышеупомянутый пакет предоставляет вам упакованную структуру axios и API, которая упакована с помощью описанного выше процесса.
axios
, не ограничиваясь Vue, также можно использовать проекты React, он подходит для любого внешнего проекта.
Код для этой статьи можно найти здесь:Таким образом, GitHub.com/111/wrap-...
Добро пожаловать на общение~
Добро пожаловать в перепечатку, пожалуйста, укажите источник:Найдите Pinyin.com/2019/12/23/…