инкапсуляция axios и стратегия обработки внешнего интерфейса

HTTP

Необходимость интерфейсной инкапсуляции

В масштабном front-end проекте, когда имеется множество интерфейсов ввода, оттока и дополнительного перехвата данных, совмещенных с управлением состоянием, для противодействия XSRF-атакам и т. д., унифицированное управление интерфейсами API стало обязательным для масштабных фронтовые проекты. Как самая популярная HTTP-библиотека на основе Promise, axios может работать как на стороне браузера, так и на стороне сервера, и стала лучшим выбором для большинства интерфейсных проектов.

POST-сериализация

пройти черезJSON.stringifyМы также можем реализовать сериализацию, но для сложныхObjectJSON.stringifyЛиния поддержки не так хороша, какqs.stringify. Таким образом, представляя библиотеку qs, qs может помочь нам сериализовать глубоко вложенные формы JSON и Array, делая нашу инкапсуляцию API совместимой с большим количеством сценариев.

var a = {name:'hehe',age:10};
 qs.stringify(a)
// 'name=hehe&age=10'
JSON.stringify(a)
// '{"name":"hehe","age":10}'

Исключение: в настоящее время большинство фоновых проектов могут получать в теле json, массив и т. д. В некоторых случаях фон может напрямую считывать строковую информацию, в этом случае форматы JSON и Array в пакете qs.stringify параметры не могут быть получены. ,Необходимо использоватьJSON.stringifyиметь дело с

axios для обработки конфигурации

Прежде чем официально выполнять вторичную инкапсуляцию axios, давайте вкратце разберемся, как axios обрабатывает элементы конфигурации: вы можете узнать из методов, предоставляемых axios, вы можете настроить конфигурацию на axios.defaults или настроить ее на перехватчике и новой конфигурации экземпляра; При чтении исходного кода обнаруживается, что конфигурация конфигурации axios реализована методом слияния:

axios.create = function create(instanceConfig) {
  return createInstance(mergeConfig(axios.defaults, instanceConfig));
};

В дополнение к axios default и конфигурации нового экземпляра также предоставляется инициализированная конфигурация по умолчанию;

var DEFAULT_CONTENT_TYPE = {
  'Content-Type': 'application/x-www-form-urlencoded'
};

function setContentTypeIfUnset(headers, value) {
  if (!utils.isUndefined(headers) && utils.isUndefined(headers['Content-Type'])) {
    headers['Content-Type'] = value;
  }
}

Конфиг аксиоса такая логика:

1. Конфигурация инициализации по умолчанию объединена с defaultconfig

2. Слить результат, полученный на первом шаге, с конфигом на новом инстансе

Благодаря анализу мы можем напрямую настроить запрашиваемый интерфейс, который удобнее адаптировать к различным сценариям за один шаг.

default config

axios предоставляет мне ряд свойств по умолчанию, которые можно напрямую отправить вaxios.defaultНекоторые присвоения атрибутов , этоaxios.defaultНазначение будет применено к используемому запросу axios; официальная документация предоставляет мне некоторые ссылки: например, установка базового URL-адреса по умолчанию, размещение токена в авторизации заголовка для запросов на основе токенов и установка типа запроса публикации;

axios.defaults.baseURL = 'https://api.example.com';
axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

Перехват запроса и перехват ответа

Будучи отличной библиотекой http-запросов, axios предоставляет мощные функции перехвата запросов и ответов.

запрос на перехват
//引入vuex
import store from '@/store'
...
axios.interceptors.request.use(config => {
  //将token添加到了request的header里面
  const token = store.state.token;
  config.headers.common['Authorization'] = token
  // loading
  return config
}, error => {
  console.log(error)
  return Promise.reject(error)
})

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

Перехват ответа

Необходимо обратить внимание на порядок выполнения перехвата ответа, выполнить первымaxios.interceptors.response.useЗатем выполните обычную обработку ответа;

// 响应拦截器
axios.interceptors.response.use(    
    response => {
        // 这里的response返回的HTTP状态码为2XX的情况,可以在这里集中处理200+JSON形式中JSON中前后端约定的状态码
    },   
    //这里的error返回的是HTTP状态码不是2XX的情况,可以在这里处理不同HTTP的status
    error => {            
        if (error.response.status) {            
            switch (error.response.status) {                
                case 401:                    
                //未登录的处理              
                case 403:
                //权限不足的处理                
                    break; 
                case 404:
              // 404请求不存在的处理
                    break;
                // 其他错误,直接抛出错误提示
                default:
                //默认处理
            }
            return Promise.reject(error.response);
        }
    }    
});

axios полностью настраивается

Благодаря конкретному анализу конфигурации axios выше, мы можем реализовать настройку различных сценариев, добавив слияние в сочетании с методом инкапсуляции; мы можем понять, например, переносить ли файлы cookie между доменами, прикреплять ли загрузку и часто ждать запросов на настройку. специальные интерфейсы и т.д.

Вы можете создать config.js

const configMap = {
  defaultConfig: {
    withCredentials: false,
    baseURL: path.baseUrl,
    headers: {
      post: { 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' },
    },
  },
  long: {
    timeout: 60000,
  },
  nocookie: {
    withCredentials: false,
  },
  ...

Внедряя в httpjs

import configMap from './config'
import { showFullScreenLoading, tryHideFullScreenLoading } from './loading'
import merge from 'lodash.merge'
...
merge(axios.defaults, configMap['defaultConfig'])
function handleTypeString(type) {
  type.toLowerCase().split('-').map(item => merge(axios.defaults, configMap[item]))
}
export default {
  post(url, data, type) {
    handleTypeString(type)
    return axios({
      method: 'post',

Таким образом, может быть реализована комбинация конфигурации нескольких запросов интерфейса, и последний будет охватывать первый один за другим, чтобы реализовать полную обработку конфигурации запросов axios;

использовать в vue

import http from "@/api/http";
import path from "@/api/path";
//配合async await更加优雅
async test() {
  const res = await http.post(path.test, params, "long-nocookie");

Некоторые люди предпочитают использовать частичную функцию, чтобы обернуть другой уровень, или они могут добавить еще один уровень инкапсуляции, чтобы использовать его непосредственно при вызове.

test(param)

Обработка глобального состояния загрузки

Инкапсулируйте загрузку.js, чтобы справиться с ситуацией, когда некоторым интерфейсам запроса URL необходимо загрузить диаграмму хризантемы; нужно установить needLoadingCount для записи и обработки нескольких ситуаций, требующих обработки интерфейса запроса загрузки.

import { Loading } from 'element-ui';
let loading; 
function startLoading() { // 使用Element loading.tart 方法
  loading = Loading.service({
    lock: true,
    text: 'loading……',
    background: 'rgba(0, 0, 0, 0.5)',
  });
}
function endLoading() { // 使用Element loading.close 方法
  loading.close();
}
//通过needLoadingCount来记录,在多个地方使用loading时候处理
let needLoadingCount = 0;
export function showLoading() {
  if (needLoadingCount === 0) {
    startLoading();
  }
  needLoadingCount++;//eslint-disable-line
}
export function tryHideLoading() {
  if (needLoadingCount >= 0) needLoadingCount--;//eslint-disable-line
  if (needLoadingCount === 0) {
    endLoading();
  }
}

Настроить в http

    if (type === 'long') {
      showFullScreenLoading()
      return axios(config).then(response=>{
         tryHideFullScreenLoading()
         rerurn response;
      })
    }
    //其他无loading的axios请求
     return axios(config)

Упаковка для нескольких окружающей среды

В спа-сценарии, где передняя и задняя части разделены, различные параметры среды, такие как baseUrl axios, предустановлены; затем они упаковываются в статические файлы, загружаются на http-сервер, такой как nginx или tomcat, и предоставляют статические файлы от локальной разработки до тестирование.Для разных фонов адреса интерфейса, установленные разными фонами, могут быть разными.Чтобы избежать упаковки по одному, нам нужно настроить пакет для разных сред доменных имен;


import merge from 'lodash.merge'
const path = {
  baseUrl: 'http://localhost:3000',
  login: '/users/login',
  test: '/test',
};
const pathMap = {
  'http://localhost:3001': { baseUrl: 'http://localhost:3001' },
    'http://localhost:3002': { baseUrl: 'http://localhost:3002',login:'/login' },
}

const getClientIdByLocation = () => {
  const { href } = window.location;
  const matchedKey = Object.keys(pathMap).filter(url => href.indexOf(url) > -1);
  merge(path, pathMap[matchedKey])
};
getClientIdByLocation();
export default path;

Путем прямой настройки объектов пути, соответствующих разным URL-адресам в pathMap, можно обрабатывать baseUrl, соответствующий разным URL-адресам, и ситуации, когда различные ситуации подмаршрутизации различны.