⚠️ Эта статья является первой подписанной статьей сообщества Nuggets, и ее перепечатка без разрешения запрещена.
Введение
Эта статья商城实践系列
В третьей статье в основном представлены некоторые конфигурации запросов интерфейса во время разработки проекта, что удобно для команд, выполняющих некоторую бизнес-обработку во время разработки.
Много друзей в ежедневной разработке, будь то использование родногоajax``、``fetch
Ну, это все еще более популярноaxios
,umi-request
Другие библиотеки инкапсуляции будут выполнять уровень бизнес-инкапсуляции для выполнения некоторой интерактивной обработки запросов, таких как: привязка токена, истечение срока действия входа, сообщение об ошибке запроса, повторная попытка интерфейса и другие общие операции.
Итак, как же инкапсулировать в проекте метод запроса интерфейса, что может уменьшить некоторое дублирование работы при соблюдении бизнес-требований?
Сегодня я возьму вас на инициализацию проекта, исходя из этого я разберу инкапсуляцию и плагины некоторых распространенных методов запросов, обрабатываемых интерфейсом. Они могут сократить обработку некоторой общей логики при совместной отладке фронтенда и бэкенда, повысить эффективность развития бизнеса, а также помочь команде реализовать автоматическую генерацию унифицированных интерфейсов и управление ими.
Существует пять основных категорий этих общих пакетов и конфигураций, и я перечислил их все на рисунке ниже.
В этой статье в качестве основного выбора библиотеки запросов используется umi-request, который представляет собой расширенную библиотеку пакетов, основанную на методе запроса на выборку. Подробнее см.: umi-запрос
Инициализировать проект
Прежде чем начать, чтобы лучше построить нашу инкапсуляцию интерфейсных запросов, нам нужно сделать некоторую предварительную работу по установке соответствующей библиотеки инструментов. Затем я проведу вас шаг за шагом, чтобы инициализировать наш файл запроса и выполнить простую инициализацию конфигурации.
Во-первых, нам нужно установитьumi-request
, кстати для инициализации проекта.
// #npm
npm install --save umi-request
// #yarn
yarn add umi-request
Затем создайте файл-оболочку, как я вutils
созданный подrequest.ts
как пакетный файл.
Наконец, в файле инициализируйте текущий экземпляр запроса черезumi-request
серединаextend
Метод инициализирует конфигурацию запроса и возвращаетRequestMethod
пример.
настроено здесь超时时间(timeout)
,错误处理函数(errorHandler)
, 请求前缀(prefix)
и другие основные параметры.
import { extend } from 'umi-request';
/** 配置request请求时的默认参数 */
const request = extend({
prefix: INTERFACE_URL,
timeout: 3000,
errorHandler
});
Когда мы инициализируем соответствующую конфигурацию, мы генерируем функцию запроса интерфейсаrequest
пример. Далее все, что нам нужно сделать, это настроить соответствующий хук-перехватчик.
перехватчик
В главе об инициализации мы упомянули перехватчики, так что же такое перехватчики и что они могут делать? Возможно многие знакомые новички во фронтенд разработке будут "запутаны" Далее я расскажу о том, что из себя представляет механизм перехватчика и как настроить перехватчик в нашем проекте.
Во-первых, механизм перехватчика, как показано на следующем рисунке. мы можем пройти拦截器
Механизм выполняет некоторую промежуточную обработку перед запросом и после ответа.
Во время этого процесса вы можете передать текущий экземпляр запросаrequest
серединаinterceptors
изAPI
, чтобы быть текущим перехватчиком.
- request.interceptors.request.use: перехватчик запросов
- request.interceptors.response.use: перехватчик ответа
В перехватчике запросов текущий запрос может быть请求地址(url)
а также请求配置(options)
Дождитесь модификации, а затем запрос будет использовать новую конфигурацию запроса для выполнения запроса интерфейса.
// request拦截器, 改变url 或 options.
request.interceptors.request.use((
url: string,
options: RequestOptionsInit
) => {
return {
url: `${url}&interceptors=yes`,
options,
}
})
В перехватчике ответа вы можетеresponse
Результат выполняет некоторую общую обработку, стоит отметить, что нам нужно использоватьresponse.clone().json()
разбиратьresponse
результат.
// 克隆响应对象做解析处理
request.interceptors.response.use(async (response: Response) => {
const data = await response.clone().json();
if (data.code === 500) {
throw new Error('throw error ......')
}
return response;
});
Здесь дается только краткое введение в перехватчик, а функция перехватчика будет расширена в следующих главах для более глубокого использования инкапсуляции.
Код и бизнес
В контексте бизнеса наша (подтверждение) система заказов использует кодовые коды для описания соответствующих идентификаторов ошибок исключений заказа. Как показано на рисунке ниже, каждый кодовый код соответствует отклонению в подтверждении заказа. В соответствии с различными уровнями и серийными номерами , мы можем выполнять политику и обработку конечного автомата в соответствии со статусом кода, возвращаемым серверной частью на странице обработки.
В реальной разработке мы используем многоcode
Вместо того, чтобы возвращать текущий статус запроса, то есть в развитии бизнеса,HTTP请求
Состояние может быть описано по наследству. Итак, давайте рассмотрим некоторые маленькие хитрости кодовой системы.
Во-первых, давайте посмотрим на структуру ответа базового запроса RESTFul:
{
code: 200,
message: ""
}
{
code: 201,
message: ""
}
{
code: 202,
message: ""
}
{
code: 203,
message: ""
}
Мы переместили состояние запроса вresponse
для обработки. При нормальном доступе к интерфейсу интерфейсному интерфейсу нужно толькоcode
выполнить операцию. Разберитесь со статусом.
Поэтому разделим код на следующие распространенные состояния ошибки:
Одним из них является статус нашего запроса интерфейса.Если этот вид оценки статуса является успешным статусом, он будет возвращен напрямую.response
серединаdata
.如果失败则直接进行错误处理。
Второй — нештатное состояние некоторых служб, в том числе системные ошибки, то есть ошибки кода. Далее следуют ошибки таких сторонних сервисов (таких как WeChat, DingTalk).
В-третьих, некоторая обратная логика в нашей разработке может быть согласована с пользовательскими кодами ошибок.
Ниже мы также перечисляем некоторые распространенные HTTP-коды в качестве идентификаторов, которых вполне достаточно в большинстве сценариев. Я не буду здесь подробно перечислять все публичные состояния.
Будь то серверная часть или интерфейсная часть, для этого есть несколько относительно полных библиотек.
export enum HTTP_STATUS {
SUCCESS = 200,
CREATED = 201,
UPDATED = 202,
DELETED = 203,
CLIENT_ERROR = 400,
AUTHENTICATE = 401,
FORBIDDEN = 403,
NOT_FOUND = 404,
SERVER_ERROR = 500,
BAD_GATEWAY = 502,
SERVICE_UNAVAILABLE = 503,
GATEWAY_TIMEOUT = 504
}
export enum CUSTOM_HTTP_CODE {
MESSAGE_TOAST = 601,
SERVICE_TRY_CATCH = 602
......
}
Когда у нас будет базовое определение кода, давайте приведем несколько реальных сценариев использования и посмотрим, как они используются.
Срок действия личности истек
Говоря об истечении срока действия личности, большинство студентов, возможно, думали об этом.401
это государство. Большая часть бизнес-логики заключается в очистке кеша и повторном входе пользователя.
В сложных сценариях существует множество определений срока действия удостоверения, включая истечение срока действия токена, единый вход, исключение удостоверения и т. д. Поэтому мы будем вызывать соответствующий метод обработки в перехватчике следующим образом:
/**
* [ u -> 401 ] 用户身份已经过期,清除后重新生成新的身份
* [ u -> 402 ] 用户身份异常,清除后重新生成新的身份
* [ u -> 403 ] 用户在其他地方登录,清除后重新生成新的身份
* */
if (
responseBody.code === 401 ||
responseBody.code === 402 ||
responseBody.code === 403
) {
clearUserTraces();
return undefined;
}
Судя по коду, мы инициируем выполнениеclearUserTraces
чтобы направить пользователя к интерфейсу входа в систему для завершения нового авторизованного входа.
/**
* 清除当前用户身份信息,并且跳转到登录页面
*/
function clearUserTraces () {
Modal.confirm({
title: '提示信息',
icon: createElement(ExclamationCircleOutlined),
content: '您当前设备信息已过期,可以取消继续留在该页面,或者重新登录。',
okText: "登录",
cancelText: "关闭",
onOk() {
history.replace('/login')
}
})
}
Настройка уведомлений
В большинстве средних и фоновых проектов задействованы панели уведомлений разных типов и состояний. отant design
Судя по стилю панели уведомлений, мы разделены наmessage
а такжеnotification
Два стиля уведомлений и разныеstatus
показывать.
На основе этой информации мы также согласовали поле с бэкендомshowMessage
Используется для управления некоторыми сообщениями об ошибках. Давайте посмотрим на текущее определение интерфейса:
type CommonResult<T = any> = {
data: T;
code: string;
showMessage:
| undefined
| false
| {
method: "message" | "notification";
type: "success" | "error" | "info" | "warning";
message: string;
description?: string;
};
};
Серверная часть может управлять подсказкой уведомления внешнего интерфейса в интерфейсе через возвращенную основную модель, которая в основном используется в бизнесе для предоставления соответствующих подсказок об успехе и неудаче операции.
Затем в перехватчике ответа я делаюshowMessage
вынес приговор. следующим образом, еслиshowMessage
выполнить, если он существуетshowMessageNotificationHandler
метод обработки всплывающей информации.
if (responseBody.showMessage) {
showMessageNotificationHandler(responseBody.showMessage)
}
showMessageNotificationHandler
Что именно вы делаете? Давайте посмотрим на реализацию метода.Общая идея реализации заключается вswitch case
Показывает различные всплывающие окна компонентов для типов и параметров, переданных из серверной части.
/**
* 显示通知弹窗
* @param showParams 显示通知参数
* @param api 当前标识
*/
export function showMessageNotificationHandler(
showParams: API.CommonResult["showMessage"],
api: string = ""
): void {
/** @name 判断是否开启了通知描述显示 */
if (showParams) {
const { method, type, message, description } = showParams;
switch (method) {
/** @name 全局提示弹窗 */
case "message":
showMessage[type](message);
break;
/** @name 通知提示弹窗 */
case "notification":
notification[type]({
message,
description,
});
break;
default:
throw new Error(
`[ request ]: 接口约定了弹窗信息参数,但是未给出使用模型,请检测当前。${api}`
);
}
}
}
После инкапсуляции мыMock
Интерфейс, чтобы увидеть эффект, мы возвращаемmessage
Всплывающая информация, чтобы увидеть эффект:
'GET /api/service-admin/v1/data/table': {
code: 40001,
message: '操作成功',
showMessage: {
method: 'message',
type: 'error',
message: '我是一个自定义的message消息',
},
data: {}
}
обработка ошибок
При обработке ошибок мы будем обрабатывать некоторые ошибки запроса. за исключениемHTTP
В дополнение к соответствующей обработке ошибок исходного состояния также необходимо настроитьcode
экспортировать, вернутьPromise.Reject
ошибка вышла. мы можемtry catch
Перехватите текущее исключение и займитесь деломcode
иметь дело с.
/** 异常处理程序 */
function errorHandler(
error: ResponseError<any> & {
code?: string | number;
}
) {
const { response, request } = error;
if (response && response.status) {
const errorText = codeMessage[response.status] || response.statusText;
const { status, url } = response;
notification.error({
message: `请求错误 ${status}: ${url}`,
description: errorText,
});
}
if (error.code && error.code === 5000) {
// todo: 上报出错人以及对应信息
throw new Error(`[fetch fail]: 接口请求失败,当前接口地址${request.url}`);
}
return Promise.reject(error);
}
В следующем примере кода мы находимся на уровне вызоваtry catch
Попробуйте захватить информацию о запросе текущего интерфейса, как показано ниже,40001
изcode
Необработанный в перехватчике ответа, таким образом перетекающий вerrorHandle
Если он все еще не обработан, то он передается вызывающей стороне для обработки:
const handleRequest = async (
props: API.TableRequestParams
): Promise<{
data: API.GithubIssueItem[];
success: boolean;
total: number;
}> => {
try {
const res = await fetchTableList(props);
return {
data: res.list,
success: true,
total: res.total,
};
} catch (throwError: unknown) {
console.log(throwError, "throwError");
return {
data: [],
success: false,
total: 0,
};
}
};
Отображение конфигурации
Когда у нас есть инкапсулированная функция запроса интерфейса, чтобы облегчить вызов членов команды, я также инкапсулировал сопоставление конфигурации.umi
Плагины для обработки преобразования функций интерфейса в спецификации интерфейса.
Как показано на рисунке ниже, мы объявим карту конфигурации, а затем абстрагируем ее в функцию. Удобно звонить во время разработки.
Здесь я расскажу вам, как его использовать.
Во-первых, яservices
В директории объявляется файл конфигурации, его стандартная форма — объект, также можно быть JSON-файлом. соглашениеKey
Значением является имя функции сопоставления.Value
да请求方式
а также请求地址
.
Object写法
module.exports = {
fetchTableList: 'GET /service-admin/v1/data/table'
}
JSON写法
{
"fetchLogin": "POST /service-admin/v1/user/login",
"fetchUserInfo": "POST /service-admin/v1/user/info"
}
Когда у нас есть файл конфигурации, соответствующая функция запроса будет сгенерирована при запуске проекта, как показано на следующем рисунке:
Плагин преобразует соответствующий файл конфигурации в функцию запроса интерфейса. Итак, как мне использовать функцию плагина для достижения этой функции? Давайте посмотрим на ядро плагина
Мы конвертируем конфигурации интерфейса в разных директориях в соответствующие конфигурации, а затем выводимtemplate
шаблон для завершения сопоставления.
Map(1) {
'/Users/wangly19/Desktop/Project/plugins/example/./constant/a.ts' => [
{
functionName: 'a',
url: '/app-services/${id}',
method: 'post',
linkParams: [Array],
exportTemp: 'const { id, ...data } = payload',
paramType: 'data'
}
]
}
Выше приведена конфигурация, которую мы сгенерировали, давайте посмотрим на содержимое шаблона.
мы можем поставитьMap
средиValue
Он преобразуется в следующий шаблон и, наконец, становится полным файлом функции интерфейса на выходе.
import request from '{{{ requestPath }}}'
import { RequestOptionsInit } from 'umi-request'
{{ #requestASTModules }}
export function {{ functionName }} <T = any, R = any>(
payload?: T = {},
options?: RequestOptionsInit = {},
): Promise<R> {
{{#exportTemp}}
{{{ exportTemp }}}
{{/exportTemp}}
{{^exportTemp}}
/* [info]: @no link params */
{{/exportTemp}}
return request( `{{{ url }}}`, {
{{ paramType }}: {{#exportTemp}}data{{/exportTemp}}{{^exportTemp}}payload{{/exportTemp}},
method: '{{ method }}',
...options
})
}
{{ /requestASTModules }}
Давайте посмотрим на эффект, как показано ниже:
ресурс
- # umi-request сетевой запрос дорога
- # Понимание архитектуры RESTful
- # xios инкапсуляция и управление интерфейсом API
Суммировать
В этой статье делается некоторая контрактная инкапсуляция для запросов в команде, а также базовая инкапсуляция бизнес-сценариев, которые могут встречаться в повседневной разработке, с разграничением ошибок интерфейса и серии успешных взаимодействий. 🤔 Объясняет, как управлять и контролировать гибкое состояние в командном бизнесе. В то же время, в последнем случае разделения в командной разработке сопоставление конфигурации управления запросами интерфейса инкапсулируется в подключаемый модуль, и членам команды не нужно заботиться об этом.request
Разнообразие методов запроса может сосредоточиться на развитии бизнеса и интерфейсных вызовах.
Наконец, мы также попробовали некоторые другие сценарии. Позже мы можем продолжить расширять и оптимизировать его.Я перечисляю эти пункты ниже:
- Механизм повторной попытки запроса интерфейса, который может
request
Бизнес-логика для повторной попытки после сбоя - Когда страница уходит, запрос интерфейса автоматически останавливается, и вы можете передать
cancelToken
а такжеcontroller.abort
отменить запрос интерфейса - Подключение к платформе управления интерфейсом, генерация конфигурации сопоставления интерфейса одним щелчком мыши, сокращение ручной работы
- Подключите swagger для генерации некоторых типов запросов интерфейса typescript
Выше приведены несколько распространенных методов упаковки для повышения эффективности команды. Для команды, по разумному соглашению между двумя сторонами, в запросе может быть размещено более общее логическое поведение, которое часто может иметь чудесные эффекты в промежуточных и внутренних проектах.
Для проекта торгового центра задача заключается не в логике реализации функций, а в оптимизации части визуального опыта и впечатлений. Если вы считаете, что статья полезна для вас, вы можете нажать 👍 и подбодрить меня. Если вы хотите узнать больше о внешних проектах электронной коммерции, Yoyos может подписаться на эту колонку.
последние хорошие статьи
- # Millions of PV Mall Practice Series — Практика по оптимизации ресурсов изображений переднего плана
- # [Избранное будет] Browser WebStorage Cache Usage Guide
- #Я и Наггетс, через год после выпуска я подписал контракт с Наггетс|2021 в середине резюме
- # Обобщить практический опыт применения TypeScript в разработке проектов
концевые сноски
Эта статья была впервые опубликована в: Nuggets Technology Community
Тип: Подписанная статья
Добавить Автора
Собрано в колонке: # Million PV Mall Practice Series
Публичный номер: Жизнь программы ItCodes