当前位置: 首页 > news >正文

《Uniapp-Vue 3-TS 实战开发》构建HTTP请求拦截器

引言

        在 UniApp 结合 TypeScript 和 Vue3 的项目开发中,请求拦截器起着至关重要的作用。它能够在请求发送前和响应接收后对数据进行统一处理,极大地提高了代码的可维护性和功能性。本文将详细解析上述代码中请求拦截器的实现及其在 UniApp-Ts-Vue3 项目中的应用,让您更直观地理解其工作流程。

一、请求拦截器的作用

        请求拦截器主要用于在请求发送到服务器之前对请求进行预处理,以及在接收到服务器响应后对响应进行后处理。在我们的代码中,它实现了以下几个关键功能:

(一)基础 URL 补全

if (!options.url.startsWith('https://')) {
  options.url = baseURLhttp + options.url;
}

      当请求的 URL 不是以 https:// 开头时,会自动将基础 URL中的 baseURLhttp(项目中发起https的请求头) (比如:https://11.12.55.666666:8080)拼接在前面。这确保了所有请求都使用正确的基础路径,尤其在开发和上线不同环境切换时,能方便地统一管理请求地址。例如,若我们有一个相对路径的请求 '/api/user',经过拦截器处理后会变为:    

 'https://11.12.55.666666:8080/api/user'。

(二)设置请求超时

options.timeout = TIMEOUT

        设置了请求的超时时间为 TIMEOUT(30000 毫秒,即 30 秒)。这是一个很重要的设置,防止请求因为网络问题或服务器故障而长时间等待,提升用户体验。当请求超过 30 秒还未得到响应时,会触发 fail 回调,提示用户网络连接失败。

(三)添加小程序端请求头标识

options.header = {
  'source - client':'miniapp',
  ...options.header, // 允许覆盖默认 header
}

        在请求头中添加了 source - client 字段,值为 miniapp,用于标识该请求来自小程序端。同时,通过 ...options.header 保留了原有的请求头信息,这样既添加了自定义标识,又不会影响其他可能需要的请求头设置。例如,在服务器端可以根据这个标识对来自小程序的请求进行特定的处理。

(四)添加 token 请求头标识

const memberStore = useMemberStore()
const token = memberStore.profile?.token
if (token) {
  options.header.token = token
}

        从状态管理(这里使用的是 Pinia 库的 useMemberStore)中获取用户的 token,并将其添加到请求头的 token 字段中。这样,服务器可以通过验证 token 来确认用户身份,实现对受保护资源的访问控制。比如,用户在登录成功后,token 被存储在状态管理中,后续的请求通过拦截器自动带上 token,无需在每个请求中手动添加。

二、拦截器的实现与注册

(一)拦截器定义

const httpInterceptor = {
  // 拦截前触发
  invoke(options: UniApp.RequestOptions) {
    // 一系列处理逻辑
  },
}

        这里定义了一个名为 httpInterceptor 的拦截器对象,它包含一个 invoke 方法。invoke 方法在每次请求被拦截时触发,接收一个 options 参数,类型为 UniApp.RequestOptions,这个参数包含了本次请求的所有配置信息,我们可以在这个方法中对这些配置进行修改。

(二)拦截器注册

uni.addInterceptor('request', httpInterceptor)
uni.addInterceptor('uploadFile', httpInterceptor)

        通过 uni.addInterceptor 方法将 httpInterceptor 注册到 request 和 uploadFile 这两种请求类型上。这意味着无论是普通的 request 请求(如获取数据、提交表单等),还是 uploadFile 文件上传请求,都会经过 httpInterceptor 的处理。

三、封装请求函数

(一)函数定义与返回值

type Data<T> = {
  categorys(categorys: any): unknown
  code: string
  msg: string
  result: T
}
// 2.2 添加类型,支持泛型
export const http = <T>(options: UniApp.RequestOptions) => {
  //1.返回Promise对象
  return new Promise<Data<T>>((resolve, reject) => {
    // 请求处理逻辑
  })
}

        定义了一个名为 http 的函数,它是对 uni.request 的封装。通过泛型 <T> 支持不同类型的响应数据。函数返回一个 Promise 对象,这样可以使用 async/await 语法来处理异步请求,使代码更简洁易读。Data<T> 类型定义了响应数据的结构,包含 code(状态码)、msg(错误信息)、result(实际数据,其类型由泛型 T 决定)以及一个 categorys 函数(这里可能是特定业务需求的函数定义,具体功能需根据业务进一步分析)。

(二)请求成功处理

success(res) {
  if (res.statusCode >= 200 && res.statusCode < 300) {
    // 获取数据成功, 调用resolve
    resolve(res.data as Data<T>)
  } else if (res.statusCode === 401) {
    // 401错误  -> 清理用户信息,跳转到登录页等,具体看你的需求逻辑
    handleUnauthorized()
    reject(res)
  } else {
    // 其他HTTP错误 -> 根据后端错误信息轻提示
    const errMsg = getHttpErrorMsg(res.statusCode)
    uni.showToast({ icon: 'none', title: errMsg })
    reject(res)
  }
}

        在 uni.request 的 success 回调中,首先判断响应状态码 statusCode。如果状态码在 200 到 299 之间,表示请求成功,将响应数据转换为 Data<T> 类型后调用 resolve,将数据传递出去。若状态码为 401,表示用户未授权,调用 handleUnauthorized 函数清理用户信息并跳转到登录页面,同时调用 reject 拒绝 Promise,传递错误响应。对于其他状态码,通过 getHttpErrorMsg 函数获取对应的错误信息,并使用 uni.showToast 进行轻提示,然后拒绝 Promise。

(三)请求失败处理

fail(err) {
  uni.showToast({
    icon: 'none',
    title: '网络连接失败',
  })
  reject(err)
}

        当请求失败(如网络故障、超时等),在 fail 回调中使用 uni.showToast 提示用户网络连接失败,并调用 reject 拒绝 Promise,传递错误信息。

四、辅助函数

(一)处理 401 未授权

const handleUnauthorized = () => {
  const memberStore = useMemberStore()
  memberStore.clearProfile()
  uni.navigateTo({ url: '/pages/login/login' })
  uni.showToast({ icon: 'none', title: '登录已过期' })
}

handleUnauthorized 函数在用户遇到 401 未授权错误时被调用。它从状态管理中获取 memberStore,调用 clearProfile 方法清理用户信息,然后使用 uni.navigateTo 跳转到登录页面,并通过 uni.showToast 提示用户登录已过期。

(二)获取 HTTP 错误信息

const getHttpErrorMsg = (code: number): string => {
  const messages: Record<number, string> = {
    400: '请求参数错误',
    403: '禁止访问',
    404: '资源不存在',
    500: '服务器错误',
    502: '网关错误'
  }
  return messages[code] || `请求失败(${code})`
}

getHttpErrorMsg 函数根据传入的 HTTP 状态码 code 返回对应的错误信息。它通过一个 Record 类型的 messages 对象存储常见状态码对应的错误描述。如果状态码在 messages 中存在,则返回对应的描述;否则返回通用的错误提示 请求失败(${code})

五、工作流程示意图

        从发起,经过拦截器处理,到服务器响应,再经过拦截器处理返回给调用者的整个流程,包括基础 URL 补全、请求头添加、超时设置等在流程中的位置]

六、总结

        通过上述代码和详细解析,我们深入了解了在 UniApp-Ts-Vue3 项目中如何构建和使用请求拦截器。请求拦截器不仅能简化请求处理逻辑,还能统一管理请求相关的配置和错误处理,提升项目的开发效率和稳定性。在实际项目中,我们可以根据具体业务需求进一步扩展和优化拦截器的功能,使其更好地服务于整个应用程序。

最后,附上完整代码:

​
/**
 * 添加拦截器:
 *   拦截 request 请求
 *   拦截 uploadFile 文件上传
 *
 * TODO:
 *   1. 非 http 开头需拼接地址
 *   2. 请求超时
 *   3. 添加小程序端请求头标识
 *   4. 添加 token 请求头标识
*/
import { useMemberStore } from '@/stores'

const baseURLhttp = 'https://11.12.55.666666:8080'; //后期注意要申请SSL证书,上线小程序的请求必须是https类型的
const TIMEOUT = 30000; // 请求超时 默认 30秒 超时

//request请求拦截
const httpInterceptor = {
  // 拦截前触发
  invoke(options: UniApp.RequestOptions) {
    //1. 补全基础路径(非 https 开头时)
    if (!options.url.startsWith('https://')) {
      options.url = baseURLhttp + options.url;
    }
	
	//设置超时时间
    options.timeout = TIMEOUT
	
    //3.添加小程序请求头
    options.header = {
      'source-client': 'miniapp',
	  ...options.header, // 允许覆盖默认 header
    }
    //4.自动添加 token 信息到请求头
    const memberStore = useMemberStore()
    const token = memberStore.profile?.token
    if (token) {
      options.header.token = token
    }
    //输出options
    // console.log(options)
  },
}

// 拦截 request 请求
uni.addInterceptor('request', httpInterceptor)
// 拦截 uploadFile 文件上传
uni.addInterceptor('uploadFile', httpInterceptor)

/**
 * 封装请求函数
 * @param  UniApp.RequestOptions
 * @returns Promise
 *  1. 返回 Promise 对象
 *  2. 获取数据成功
 *    2.1 提取核心数据 res.data
 *    2.2 添加类型,支持泛型
 *  3. 获取数据失败
 *    3.1 401错误  -> 清理用户信息,跳转到登录页
 *    3.2 其他错误 -> 根据后端错误信息轻提示
 *    3.3 网络错误 -> 提示用户换网络
*/

type Data<T> = {
  categorys(categorys: any): unknown
  code: string
  msg: string
  result: T
}
// 2.2 添加类型,支持泛型
export const http = <T>(options: UniApp.RequestOptions) => {
  //1.返回Promise对象
  return new Promise<Data<T>>((resolve, reject) => {
    uni.request({
      ...options,
      //2.请求成功
      success(res) {
        // if (res.statusCode == 0 || (res.statusCode >= 200 && res.statusCode < 300)) {
        if (res.statusCode >= 200 && res.statusCode < 300) {
          // 获取数据成功, 调用resolve
          resolve(res.data as Data<T>)
        } else if (res.statusCode === 401) {
          // 401错误  -> 清理用户信息,跳转到登录页
		  handleUnauthorized()
          reject(res)
        } else {
          // 其他HTTP错误 -> 根据后端错误信息轻提示
		  const errMsg = getHttpErrorMsg(res.statusCode)
		  uni.showToast({ icon: 'none', title: errMsg })
          reject(res)
        }
      },
      // 响应失败
      fail(err) {
        uni.showToast({
          icon: 'none',
          title: '网络连接失败',
        })
        reject(err)
      },
    })
  })
}

/**
 * 处理 401 未授权
 */
const handleUnauthorized = () => {
  const memberStore = useMemberStore()
  memberStore.clearProfile()
  uni.navigateTo({ url: '/pages/login/login' })
  uni.showToast({ icon: 'none', title: '登录已过期' })
}

/**
 * 获取 HTTP 错误信息
 */
const getHttpErrorMsg = (code: number): string => {
  const messages: Record<number, string> = {
    400: '请求参数错误',
    403: '禁止访问',
    404: '资源不存在',
    500: '服务器错误',
    502: '网关错误'
  }
  return messages[code] || `请求失败(${code})`
}

​

http://www.dtcms.com/a/123007.html

相关文章:

  • Windows 2016 如何关闭自动更新
  • HLSL Complex Shapes With For Loops
  • Linux启动端口,Windows 看是否通
  • 使用 Vue + PDF.js 构建在线 PDF 阅读器(支持目录与缩放)
  • Petalinux最简开发
  • (2)网络学习之堡垒机
  • 如何避免Python爬虫重复抓取相同页面?
  • 【数据结构】树状数组
  • RTT中断管理学习
  • 苹果电脑MAC系统安装
  • 【MySQL篇】mysqlpump和mysqldump参数区别总汇
  • 【C++游戏引擎开发】第11篇:GLFW、GLAD环境搭建与第一个三角形渲染
  • 09-Spring 与线程安全:IOC 与多线程下的坑与解法
  • 解锁Midjourney创作潜能:超详细提示词(Prompts)分类指南
  • 【42期获取股票数据API接口】如何用Python、Java等五种主流语言实例演示获取股票行情api接口之沪深指数最新分时BOLL数据及接口API说明文档
  • 三、使用Keil5新建STM32工程
  • 【学Rust写CAD】29 Alpha256结构体(alpha256.rs)
  • torch.meshgrid()
  • 【OCR】总结目前流行的主要的OCR工具
  • Jenkins安装流程
  • 联邦学习研读笔记
  • printf
  • 【NLP 面经 9、逐层分解Transformer】
  • 第十一章 Python语言-高阶技巧(终章)
  • Dubbo(44)如何排查Dubbo的服务依赖问题?
  • 17. git pull
  • 6、nRF52xx蓝牙学习(nrf_gpiote.c库函数学习)
  • 基于 AI智能体、大模型、RAG、Agent 等技术构建公司内部闭环智能问答系统的详细方案,结合 Spring Boot + Vue 管理系统 的改造思路
  • Http代理服务器选型与搭建
  • Starrocks的Bitmap索引和Bloom filter索引以及全局字典