Umi-Request Network Request Road

JavaScript

Автор Ли Тоу Ант Техническая группа по работе с финансовыми данными

задний план

В процессе разработки бизнес-приложений среднего уровня мы обнаружили следующие проблемы в ссылке запроса:

  1. Библиотеки запросов разные, а единообразия нет.Каждый раз, когда запускается новое приложение, набор логики уровня запросов необходимо повторно реализовывать, а API библиотеки запросов необходимо заново изучать при переключении приложений.
  2. Несоответствия дизайна интерфейса каждого приложения, путаница.Студентам, работающим с фронтендом и бэкендом, необходимо каждый раз переделывать формат интерфейса, а студентам фронтенда нужно заново понимать формат интерфейса при переключении приложений, прежде чем заняться развитием бизнеса.
  3. Документация интерфейса поддерживается различными способами.Некоторые из них находятся в Yuque (облачной базе знаний), некоторые в RAP (инструмент управления интерфейсом с открытым исходным кодом), а некоторые можно узнать, только прочитав исходный код Будь то техническое обслуживание, имитация данных или общение, это пустая трата рабочей силы. .

В ответ на вышеперечисленные вопросы предлагаемУправление уровнем запроса,надеяться наЧерез унифицированную библиотеку запросов, спецификацию дизайна интерфейса запроса спецификации, документ унифицированного интерфейсаЭти три шага, три этапа запрошенной ссылкиэффективность и спецификация,Это снижает коммуникационные и трудовые затраты, которые разработчики тратят на проектирование интерфейса, обслуживание документации и разработку логики уровня запросов. в,В качестве базовой технической поддержки унифицированная библиотека запросов нуждается в заблаговременном создании базы для обеспечения стабильной и полной функциональной поддержки верхнего уровня, на основе чего и появился umi-request.

umi-request

umi-requestЭто библиотека HTTP-запросов с открытым исходным кодом, основанная на инкапсуляции выборки. Она призвана предоставить разработчикам унифицированный метод вызова API, упростить метод использования и предоставить общие функции уровня запроса:

  • Автоматическая сериализация параметров URL
  • Режим отправки данных POST упрощен
  • Обработка возврата ответа упрощена
  • обработка тайм-аута запроса
  • запросить поддержку кеша
  • Обработка кодирования GBK
  • Единая обработка ошибок
  • Запрос на отмену поддержки
  • HTTP-запрос среды узла
  • Механизм перехватчика
  • Механизм промежуточного программного обеспечения Onion

Сходства и различия с выборкой и аксиомами?

характеристика umi-request fetch axios
выполнить fetch Встроенная поддержка браузера XMLHttpRequest
запрос упрощен
пост упрощенный
тайм-аут
тайник
проверка ошибок
обработка ошибок
перехватчик
приставка
суффикс
процесс гбк
промежуточное ПО
отменить запрос

Нижний уровень umi-request отказывается от XMLHttpRequest, который имеет грубый дизайн и не соответствует разделению ответственности, и выбирает выборку, которая является более семантической и основана на стандартной реализации Promise (подробнее).смотрите подробности); в то же время изоморфизм удобнее использоватьisomorphic-fetch(в настоящее время встроено) и на основе различных сценариев бизнес-приложений для извлечения общих возможностей запросов и поддержки быстрой настройки, такой как пост-упрощение, префикс и суффикс, проверка ошибок и т. д.

Легко начать

Установить

npm install --save umi-request

Выполнить GET-запрос

import request from "umi-request";
request
  .get("/api/v1/xxx?id=1")
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });
// 也可将 URL 的参数放到 options.params 里
request
  .get("/api/v1/xxx", {
    params: {
      id: 1
    }
  })
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

воплощать в жизнь POST просить

import request from "umi-request";
request
  .post("/api/v1/user", {
    data: {
      name: "Mike"
    }
  })
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

Создание универсальной конфигурации

Запросы обычно имеют некоторые общие настройки, мы не хотим добавлять их по одному в каждом запросе, такие как общие префиксы, суффиксы, информация заголовка, обработка исключений и т. д., тогда мы можем передатьextendЧтобы создать новый экземпляр umi-request, чтобы уменьшить количество повторяющегося кода:

import { extend } from "umi-request";

const request = extend({
  prefix: "/api/v1",
  suffix: ".json",
  timeout: 1000,
  headers: {
    "Content-Type": "multipart/form-data"
  },
  params: {
    token: "xxx" // 所有请求默认带上 token 参数
  },
  errorHandler: function(error) {
    /* 异常处理 */
  }
});

request
  .get("/user")
  .then(function(response) {
    console.log(response);
  })
  .catch(function(error) {
    console.log(error);
  });

Встроенные возможности общих запросов

Fetch сам по себе не предоставляет таких возможностей, как тайм-аут запроса, кэширование, отмена и т. д., но часто требуется в бизнес-разработке, поэтому umi-request инкапсулирует и строит общие возможности запросов, чтобы уменьшить повторную разработку:

{
  // 'params' 是即将于请求一起发送的 URL 参数,参数会自动 encode 后添加到 URL 中
  // 类型需为 Object 对象或者 URLSearchParams 对象
  params: { id: 1 },

  // 'paramsSerializer' 开发者可通过该函数对 params 做序列化(注意:此时传入的 params 为合并了 extends 中 params 参数的对象,如果传入的是 URLSearchParams 对象会转化为 Object 对象
  paramsSerializer: function (params) {
    return Qs.stringify(params, { arrayFormat: 'brackets' })
  },

  // 'data' 作为请求主体被发送的数据
  // 适用于这些请求方法 'PUT', 'POST', 和 'PATCH'
  // 必须是以下类型之一:
  // - string, plain object, ArrayBuffer, ArrayBufferView, URLSearchParams
  // - 浏览器专属:FormData, File, Blob
  // - Node 专属: Stream
  data: { name: 'Mike' },

  // 'headers' 请求头
  headers: { 'Content-Type': 'multipart/form-data' },

  // 'timeout' 指定请求超时的毫秒数(0 表示无超时时间)
  // 如果请求超过了 'timeout' 时间,请求将被中断并抛出请求异常
  timeout: 1000,

  // 'prefix' 前缀,统一设置 url 前缀
  // ( e.g. request('/user/save', { prefix: '/api/v1' }) => request('/api/v1/user/save') )
  prefix: '',

  // 'suffix' 后缀,统一设置 url 后缀
  // ( e.g. request('/api/v1/user/save', { suffix: '.json'}) => request('/api/v1/user/save.json') )
  suffix: '',

  // 'credentials' 发送带凭据的请求
  // 为了让浏览器发送包含凭据的请求(即使是跨域源),需要设置 credentials: 'include'
  // 如果只想在请求URL与调用脚本位于同一起源处时发送凭据,请添加credentials: 'same-origin'
  // 要改为确保浏览器不在请求中包含凭据,请使用credentials: 'omit'
  credentials: 'same-origin', // default

  // 'useCache' 是否使用缓存,当值为 true 时,GET 请求在 ttl 毫秒内将被缓存,缓存策略唯一 key 为 url + params 组合
  useCache: false, // default

  // 'ttl' 缓存时长(毫秒), 0 为不过期
  ttl: 60000,

  // 'maxCache' 最大缓存数, 0 为无限制
  maxCache: 0,

  // 'charset' 当服务端返回的数据编码类型为 gbk 时可使用该参数,umi-request 会按 gbk 编码做解析,避免得到乱码, 默认为 utf8
  // 当 parseResponse 值为 false 时该参数无效
  charset: 'gbk',

  // 'responseType': 如何解析返回的数据,当 parseResponse 值为 false 时该参数无效
  // 默认为 'json', 对返回结果进行 Response.text().then( d => JSON.parse(d) ) 解析
  // 其他(text, blob, arrayBuffer, formData), 做 Response[responseType]() 解析
  responseType: 'json', // default

  // 'errorHandler' 统一的异常处理,供开发者对请求发生的异常做统一处理,详细使用请参考下方的错误处理文档
  errorHandler: function(error) { /* 异常处理 */ },
}

Механизм промежуточного программного обеспечения для облегчения расширения

Приложение сложной сцены имеет индивидуальные требования к обработке до и после запроса, в дополнение к базовой встроенной возможности также необходимо улучшить собственное расширение на основе этого введения umi-запроса ** механизм промежуточного программного обеспечения, ** Выберите тип модели KOA Circle:

中间件洋葱图

(луковая диаграмма промежуточного программного обеспечения)

Как видно из рисунка выше, каждый слой луковых колец является промежуточным ПО, и запрос будет выполняться дважды через промежуточное ПО. Разработчики могут легко реализовать расширенную обработку до и после запроса в соответствии с потребностями бизнеса:

import request from "umi-request";

request.use(function(ctx, next) {
  console.log("a1");
  return next().then(function() {
    console.log("a2");
  });
});
request.use(function(ctx, next) {
  console.log("b1");
  return next().then(function() {
    console.log("b2");
  });
});
// 执行顺序如下:
// a1 -> b1 -> b2 -> a2

// 使用 async/await 能让结构、顺序更清晰明了:
request.use(async (ctx, next) => {
  console.log("a1");
  await next();
  console.log("a2");
});
request.use(async (ctx, next) => {
  console.log("b1");
  await next();
  console.log("b2");
});

const data = await request("/api/v1/a");

// 执行顺序如下:
// a1 -> b1 -> b2 -> a2

Принцип реализации

Так как же реализован промежуточный механизм лукового кольца? Он в основном состоит из массива промежуточного программного обеспечения и комбинации промежуточного программного обеспечения.Первый отвечает за хранение смонтированного промежуточного программного обеспечения, а второй отвечает за объединение промежуточного программного обеспечения в соответствии со структурой лука и возврат реальной исполняемой функции:

промежуточное ПО для хранения

class Onion {
  constructor() {
    this.middlewares = [];
  }
  // 存储中间件
  use(newMiddleware) {
    this.middlewares.push(newMiddleware);
  }
  // 执行中间件
  execute(params = null) {
    const fn = compose(this.middlewares);
    return fn(params);
  }
}

ПО промежуточного слоя композиции

в приведенном выше кодеcomposeЭто реализация функции комбинированного промежуточного программного обеспечения, и упрощенная логика выглядит следующим образом (смотрите подробности):

export default function compose(middlewares) {
  return function wrapMiddlewares(params) {
    let index = -1;
    function dispatch(i) {
      index = i;
      const fn = middlewares[i];
      if (!fn) return Promise.resolve();
      return Promise.resolve(fn(params, () => dispatch(i + 1)));
    }
    return dispatch(0);
  };
}

Функция компоновки проходитdispatch(0)Первое промежуточное ПО выполняется первымfn(params, () => dispatch(i +1))и предоставить() => dispatch(i +1)В качестве входных данных каждое промежуточное ПО может возвращаться и продолжать обрабатывать свою собственную транзакцию после выполнения следующего промежуточного ПО, пока все промежуточное ПО не будет завершено и выполнено.Promise.resolve(), формируя промежуточный механизм лукового кольца.

Богатые возможности запроса

Сталкиваясь с приложениями с несколькими терминалами и несколькими устройствами, umi-request не только поддерживает HTTP-запросы браузера, но также удовлетворяет требованиям среды узла, пользовательским запросам ядра и другим возможностям.

Поддержка среды узла для отправки HTTP-запросов

Запросить поддержку среды Node на основе ISOMORPHIC-FETCH:

const umi = require("umi-request");
const extendRequest = umi.extend({ timeout: 10000 });

extendRequest("/api/user")
  .then(res => {
    console.log(res);
  })
  .catch(err => {
    console.log(err);
  });

Возможность поддерживать пользовательский запрос ядра

Мобильные приложения обычно имеют свои собственные протоколы запросов, такие как запросы RPC. Внешний интерфейс будет вызывать клиентский API запросов через SDK. umi-request позволяет разработчикам инкапсулировать свои собственные возможности запросов, например:

// service/some.js
import request from "umi-request";
// 自定义请求内核中间件
function SDKRequest(ctx, next) {
  const { req } = ctx;
  const { url, options } = req;
  const { __umiRequestCoreType__ = "normal" } = options;

  if (__umiRequestCoreType__.toLowerCase() !== "SDKRequest") {
    return next();
  }

  return Promise.resolve()
    .then(() => {
      return SDK.request(url, options); // 假设已经引入了 SDK 并且能通过 SDK 发起对应请求
    })
    .then(result => {
      ctx.res = result; // 将结果注入到 ctx 的 res 里
      return next();
    });
}

request.use(SDKRequest, { core: true }); // 引入内核中间件

export async function queryUser() {
  return request("/api/sdk/request", {
    __umiRequestCoreType__: "SDKRequest", // 声明使用 SDKRequest 来发起请求
    data: []
  });
}

Суммировать

С улучшением возможностей umi-request он смог поддерживать запросы из различных сценариев и конечных приложений.Для фронтенд-разработки требуется только освоить набор вызовов API для реализации многоконечной разработки, больше не нужно обращать внимание на реализацию базового протокола и больше сосредоточиться на разработке интерфейса. Основываясь на этом, umi-request может делать больше вещей внизу, таких как фиктивные данные, автоматическая идентификация типов запросов, мониторинг исключений интерфейса и отчетность, проверка спецификации интерфейса и т. д., и, наконец, достигать цели управления запросами. В umi-request еще много способностей, не упомянутых в тексте, если интересно, то ознакомьтесь.Подробная документация, если у вас есть хорошие предложения и потребности, вы также можете упомянутьissue.

giuthub blog Оригинальная ссылка