普通视图

发现新文章,点击刷新页面。
昨天以前首页

uni.request 二次封装

2026年1月30日 10:30

基于uni.request api进行二次封装

核心功能

  • 响应内容格式和请求参数格式类型定义
  • 请求拦截器与响应拦截器配置
  • 设置请求头和params参数处理
  • 加载提示与自定义提示文本
  • 错误统一处理
  • 接口缓存
  • 取消请求功能
  • 失败自动重试机制
  • 并发请求控制

核心代码

// 响应内容格式
export interface InResult<T> {
  code: number | string
  message: string
  success: boolean
# data: T
}
// 请求参数格式
interface RequestOptions {
  baseURL?: string
  url: string
  method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
  data?: Record<string, any>
  params?: Record<string, any>
  header?: Record<string, string>
  loading?: boolean // 是否显示加载中提示
  loadingText?: string // 加载中提示文本
  removeToken?: boolean // 是否移除token
  cache?: boolean // 是否缓存响应结果
  returnResponse?: boolean // 直接返回响应
}

// 设置请求头
function setRequestHeaders(url: string) {
  const LOGIN_URL = '/auth/oauth2/token'
  if (url.includes(LOGIN_URL)) {
    return { Authorization: `Basic Z2VveHNwYWNlOmdlb3hzcGFjZQ==` }
  }
  const token = uni.getStorageSync('token')
  if (token) {
    return { Authorization: `Bearer ${token}` }
  }
  return {} as Record<string, string>
}
// 请求和响应拦截器
function requestAndResponseInterceptor() {
  uni.addInterceptor('request', {
    // 调用前置拦截器
    invoke(options: RequestOptions) {
      if (options.loading) {
        uni.showLoading({
          title: options.loadingText || '加载中...',
          mask: true,
        })
      }

      options.header = {
        ...options.header,
        ...setRequestHeaders(options.url),
      }

      // 移除token
      if (options.removeToken) {
        delete options.header.Authorization
      }

      // 处理params 参数
      if (options.params) {
        const urlPrams: string[] = []
        Object.keys(options.params).forEach((key) => {
          urlPrams.push(`${key}=${options.params![key]}`)
        })
        if (options.url.includes('?')) {
          options.url += urlPrams.join('&')
        }
        else {
          options.url += `?${urlPrams.join('&')}`
        }
      }
      return options
    },

    // 调用后置拦截器
    success(res) {
      return res
    },
    fail(err) {
      uni.showToast({
        title: '网络请求失败',
        icon: 'none',
      })
      return Promise.reject(err)
    },

    complete(option) {
      console.log('option.errMsg', option.errMsg)
      setTimeout(() => {
        uni.hideLoading()
      }, 15000)
    },
  })
}

// 调用请求拦截器和响应拦截器
requestAndResponseInterceptor()

const cacheMap = new Map<string, any>()
// 封装网络请求
export async function request(options: RequestOptions): Promise<any> {
  const { baseURL, url, header = {}, cache, returnResponse } = options
  // 合并配置
  const config = {
    ...options,
    url: url.startsWith('http') ? options.url : baseURL + options.url,
    header: {
      'Content-Type': 'application/json',
      ...header, // 允许自定义header
    },
    timeout: 10000, // 超时时间(ms)
  }

  if (cache) {
    if (cacheMap.has(url)) {
      return cacheMap.get(url)
    }
  }

  try {
    const response = await uni.request(config)

    if (options.loading) {
      uni.hideLoading()
    }
    // 响应拦截器
    if (response.statusCode === 200) {
      const data = returnResponse ? response : response.data
      if (cache) {
        cacheMap.set(url, data)
      }

      // @ts-expect-error 判断异常
      if (response.data.code !== '20000') {
        // @ts-expect-error 判断异常
        toast(response.data.msg, {
          icon: 'fail',
        })
      }

      return data
    }
    if (response.statusCode === 401) {
      toast('登录已过期,请重新登录!', {}, () => {
        uni.redirectTo({
          url: '/user/login/index',
        })
      })
    }
    else {
      toast('系统服务异常!')
    }
  }
  catch (error) {
    return Promise.reject(error)
  }
}

toast 封装代码

export function toast(title: string, options?: { duration?: number, icon?: 'success' | 'loading' | 'error' | 'none' | 'fail' | 'exception', mask?: boolean }, callback?: () => void) {
  const { mask = true, duration = 1000, icon = 'none' } = options || {}

  if (title && title.length > 14) {  // 当作字符长度>14时使用showModal展示
    uni.showModal({
      content: title,
      showCancel: false,
      success() {
        if (callback && typeof callback === 'function') {
          const timer = setTimeout(() => {
            callback()
            clearTimeout(timer)
          }, duration)
        }
      },
    })
  }
  else {
    uni.showToast({
      title,
      message: title,
      icon,
      mask,
      duration,
      success() {
        if (callback && typeof callback === 'function') {
          const timer = setTimeout(() => {
            callback()
            clearTimeout(timer)
          }, duration)
        }
      },
    })
  }
}

使用示例

import { type InResult, request } from '@/utils/request'

export interface IUser {
    id: string,
    name: string,
    age?: number
}

export function getUserList(data: any): Promise<InResult<{ records: Array<IUser>, total: number }>> {
  return request({
    baseURL,
    url: '/user/page',
    method: 'POST',
    params: data,
    loading: true,
  })
}
❌
❌