Как инкапсулировать аксиомы в проекте

внешний интерфейс axios
Как инкапсулировать аксиомы в проекте

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

Преимущества упаковки axios

Пакет преимуществ Axios является единым процессом, повышение эффективности и простоты обслуживания.

Вы можете использовать интерфейс запроса axios, как показано ниже.

axios.get('http://localhost:10086/user?ID=12345')
  .then(response => {
    //成功后的操作...
  })
  .catch(error => {
    //失败后的操作...
  });

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

Идеи упаковки

Нам нужно централизованно настроить axios за один раз и адаптировать конфигурацию к большинству сценариев нашего проекта. Мы можем создать файл js, создать новый экземпляр axios с настраиваемой конфигурацией, а затем выполнить базовую настройку экземпляра, добавить необходимую обработку перед запросом (обработка тела запроса), после запроса (обработка возвращаемого результата) и другие этапы. , Затем экспортируйте его для использования.

Приоритет конфигурации

Конфигурации объединяются в порядке приоритета. Порядок такой: вlib/defaults.jsНайдите значение по умолчанию библиотеки, а затем примерыdefaultsатрибут, наконец, запрошенныйconfigпараметр. (Таким образом, мы также можем обрабатывать некоторые специальные сценарии отдельно)

lib/defaults.js в файле библиотеки axios в папке node_modules.

1631849876(1).png

Пользовательские значения по умолчанию для экземпляра
const instance = axios.create({
  baseURL: 'https://api.example.com'
});
Запрашиваемые параметры конфигурации
axios({   
method:'get',   
url:'http://bit.ly/2mTM3nY',   
responseType:'stream' }).then(function(response) {   response.data.pipe(fs.createWriteStream('ada_lovelace.jpg')) });

конфигурация экземпляра axios

1. Определите некоторую общую конфигурацию

  • setBaseUrl

BaseUrl обычно делится на несколько адресов, таких как производство, разработка и тестирование. Мы можем получить config.js для хранения. Если это vue или react, мы можем создать новый env и другие файлы для хранения. Следующий baseUrl использует реагировать на переменные среды.

  • Установить время ожидания запроса тайм-аута
  • Установите формат Content-Type запроса данных (есть application/x-www-form-urlencoded, multipart/form-data, application/json...) и т. д.
import axios from 'axios'

export const request = createAxiosInstance()

function createAxiosInstance () {
  const instance = axios.create({
    baseURL: process.env.REACT_APP_BASE_URL,
    timeout: 5000,
    headers: {
      // 可定义统一的请求头部
      post: {
        'Content-Type': 'application/json'
      }
      ...
    }
  })
  return instance
}

2. Добавляем некоторые нужные нам операции перед запросом,

  • Например, вам нужно добавить токен в заголовок запроса
  • Пустая обработка параметров запроса

(В примере на рисунке ниже передается пустое имя и personId, что вызовет двусмысленность. Независимо от того, нужно ли получить значение параметра пустым или игнорировать эти параметры, некоторые серверные части будут выполнять некоторую обработку, но внешний интерфейс должен стараться избегать этого~)

1632053184(1).png

  • Включать эффект анимации загрузки каждый раз, когда запрашивает интерфейс и т.д.
  // 添加请求拦截器(在发送请求之前做些什么)
  instance.interceptors.request.use((config) => {
      //可添加开启loading效果的函数
      loading.open()  
      //token 存在就添加到请求头里
      token && (config.headers.Authorization = token)
     // 过滤请求参数中的 null undefined ''的函数
      cleanObject()
      return config
  })

3. После возврата запроса добавьте операцию перехвата,

  • Обработать возвращенные данные успешно

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

  • Отчет об исключении после сбоя унифицированной обработки

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

 // 添加响应拦截器(对响应数据做点什么)
  instance.interceptors.response.use((response) => {
   //可添加关闭loading效果的函数
      loading.close()  
      //解构出返回结果的数据
      const res = response.data
      //对自定义code码进行判断,将成功的数据返回出去
      const validateStatus = /^(2|3)\d{2}$/ //code为2或3开头的视作请求成功
      if (validateStatus.test(res.code)) {
        return res.data      //直接return出去我们需要的data
      }
      //判断失败的code码并作出提示等操作
      if (res.code === 401) {
        message.error(res.msg)
      } else {
        message.warning(res.msg)
      }
      return Promise.reject(res)
      },
      (error) => {
      loading.close() 
      if (error.response.status === 401) {
        message.error('token失效,请重新登录!')
        removeStorageToken()
        setTimeout(() => {
          window.location.href = '/login'
        }, 2000)
      } else {
        if (!window.navigator.onLine) {
          message.warning('网络异常,请检查网络是否正常连接')
        } else if (error.code === 'ECONNABORTED') {
          message.warning('请求超时')
        } else {
          message.warning('服务器异常,请联系管理员')
        }
      }
      return Promise.reject(error) // 将错误继续返回给到具体页面
    }
      )

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

Унифицированное управление методами интерфейса запросов

Как правило, мы будем писать все методы запроса интерфейса вместе для унифицированного управления, а также их легко найти и поддерживать при последующих изменениях.1632057564(1).pngМы можем создать новую папку (например, apiList) для управления запросами API и поместить в нее наши различные файлы запросов (здесь по функциям). Например, user.js хранит пользовательские запросы и так далее. Тогда страница может напрямую ссылаться на метод для вызовов интерфейса.

import { request } from '../axios'

// 获取用户信息
export function getUserInfo (userId) {
  return request.get(`/sys/user/info/${userId}`)
}

Вы можете напрямую вызвать метод на компоненте или странице~

Наконец-то поставили про полный образец! Вы можете обратиться к ~

Этот пример конфигурации подходит для Vue или реагирует. Конечно, конфигурация каждого проекта будет немного отличаться. Небольшие партнеры должны изменять конфигурацию и расширяться в соответствии со своими собственными проектами ~

import axios from 'axios'

export const request = createAxiosInstance()

function createAxiosInstance () {
  const instance = axios.create({
    baseURL: process.env.REACT_APP_BASE_URL,
    timeout: 5000,
    headers: {
      // 可定义统一的请求头部
      post: {
        'Content-Type': 'application/json'
      }
      ...
    }
  })
   // 添加请求拦截器(在发送请求之前做些什么)
  instance.interceptors.request.use((config) => {
      //可添加开启loading效果的函数
      loading.open()  
      //token 存在就添加到请求头里
      token && (config.headers.Authorization = token)
     // 过滤请求参数中的 null undefined ''的函数
      cleanObject()
      return config
  })
  // 添加响应拦截器(对响应数据做点什么)
  instance.interceptors.response.use((response) => {
   //可添加关闭loading效果的函数
      loading.close()  
      //解构出返回结果的数据
      const res = response.data
      //对自定义code码进行判断,将成功的数据返回出去
      const validateStatus = /^(2|3)\d{2}$/ //code为2或3开头的视作请求成功
      if (validateStatus.test(res.code)) {
        return res.data
      }
      //判断失败的code码并作出提示等操作
      if (res.code === 401) {
        message.error(res.msg)
      } else {
        message.warning(res.msg)
      }
      return Promise.reject(res)
      },
      (error) => {
      loading.close()  //可添加关闭loading效果的函数
      if (error.response.status === 401) {
        message.error('token失效,请重新登录!')
        removeStorageToken()
        setTimeout(() => {
          window.location.href = '/login'
        }, 2000)
      } else {
        if (!window.navigator.onLine) {
          message.warning('网络异常,请检查网络是否正常连接')
        } else if (error.code === 'ECONNABORTED') {
          message.warning('请求超时')
        } else {
          message.warning('服务器异常,请联系管理员')
        }
      }
      return Promise.reject(error) // 将错误继续返回给到具体页面
    }
      )
  
  return instance
}