uniapp加TS对网络请求及拦截器的封装

2,996 阅读3分钟

前言

公司最近正在做使用uniapp混合开发移动端App,开发过程中,每次写接口,都需要写很多重复性代码。因此想对原生请求方式做个封装,减少写重复性代码。

准备

定义服务器返回值类型

每个家公司后端肯能返回的格式不同,我们公司请求数据后,返回的数据格式是status,msg,data这三个字段,其中data我们使用泛型来定义他,因为data类型可能各种各样

export interface IResponse<T = any> {
  status: number
  msg: string
  data: T
}

开始封装

一、拦截器

顾名思义,拦截器的作用就是在发送网络请求前后,对请求头或相应结果等进行一些特殊处理的方法。 uni.addInterceptor('request', OBJECT) ,将拦截 uni.request()

参数名说明
invoke拦截前触发
success成功回调拦截
fail失败回调拦截
complete完成回调拦截

whiteApiList是白名单,不用携带token就可以请求的接口,除白名单外的接口,访问一律跳转到登录页面。

toLoginPage是对uni.navigateTo跳转方法的封装。直接跳转登录页面。

getLocal是对uni.getStorage的封装

// interceptor.ts

// 根地址
export const baseUrl = 'https://test.com'

// 白名单,不需要携带token就允许被访问的接口
const whiteApiList = ['/api/login/mobile', '/api/login', '/api/register/verify', '/api/register/reset']

export const interceptor = () => {

  uni.addInterceptor('request', {
  
  // 请求拦截器
    invoke(args) {
    
    // 加载loading
      uni.showLoading({
        title: '加载中...'
      })
      
      // 当本地没有token,并且接口地址没在白名单内,一律跳转登录页面
      if (!getLocal<string>('token') && !whiteApiList.includes(args.url)) {
        toLoginPage()
        uni.hideLoading()
        return false
      }
      // request 触发前拼接 url
      args.url =  baseUrl + args.url
      
      //设置请求头及token
      args.header = {
        'content-type': args.method === 'POST' ? 'application/json' : 'application/x-www-form-urlencoded',
        'Authori-zation': 'Bearer ' + getLocal<string>('token')
      }
      console.log(args.header)
    },
    
    // 响应拦截器,可以对数据进行预处理
    success(args) {
      uni.hideLoading()
      
    },
    fail(err) {
      console.log('interceptor-fail', err)
      console.log('请求失败')
      uni.hideLoading()
    },
    complete(res) {
      uni.hideLoading()
    }
  })
}

二、get请求

不封装的时候使用get请求

uni.request({
  url: url, // 请求地址
  method: 'GET',  // 请求方式
  data, // 发送的数据
  success: (res: any) => {
    if (res.statusCode === 200) {
      console.log(res.data) //请求成功的回调
    } else {
      console.log(res) // 请求失败的回调
    }
  }
})

通过上面的例子我们发现,只请求一个接口就需要写十几行代码,何况项目中可能有几十个接口,甚至上百个,如果不封装的话,代码冗余程度难以想象。 封装 通过传入泛型T,我们可以知道,我们想要的数据是什么样的结构. url是接口地址,data是个对象类型的参数。通过Promise获取到成功状态的值。当需要发送get请求是我们直接调用get方法传入参数就好,不用再写重复的代码

export const get = <T>(url: string, data: Record<string, any> = {}) => {
  return new Promise<IResponse<T>>((resolve, reject) => {
    uni.request({
      url: url,
      method: 'GET',
      data,
      success: (res: any) => {
        if (res.statusCode === 200) {
          resolve(res.data)
        } else {
          reject(res)
        }
      }
    })
  })
}
三、post请求

post封装方式和get封装方式类似,同样传入泛型,通过Promise获取到成功状态的值。

// post请求
export const post = <T>(url: string, data: Record<string, any> = {}) => {
  return new Promise<IResponse<T>>((resolve, reject) => {
    uni.request({
      url: url,
      method: 'POST',
      data,
      success: (res: any) => {
        console.log(res)
        if (res.statusCode === 200) {
          resolve(res.data)
        } else {
          reject(res)
        }
      }
    })
  })
}

使用方法

通过查看接口文档,我们可以先定义接口要返回数据类型。

登录接口:登录接口使用post请求。一般会返回{token:'xxxxx', msg:'登录成功'}

获取用户信息:使用get请求,传入用户id。返回{name:'xx', age:18, gender:'男'}

从接口文档我们可以知道,接口将要返回我们什么样的数据,我们可以提前定义这些数据类型。方便我们后续操作。

post用例
//导入post方法
import { post } from "@/xxx"

// 登录接口 
 const loginUrl = '/api/login'

//服务器要返回的数据类型
interface ILoginResult {
    token:string
    msg: string
}

// 用户输入的数据
const loginInfo = {username:'xia', password:123}

//传入泛型
post<ILoginResult>(loginUrl,loginInfo).then({data, status} => {
    if(status == 200) {
        // 数据获取成功
        console.log(data.token)
        console.log(data.msg)
    }
})
get用例
//导入get方法
import { get } from "@/xxx"

// 用户信息接口
 const userUrl = '/api/userinfo'

//服务器要返回的数据类型
interface IUserInfo {
    name:string
    age:18
    gender:string
}

// 传入用户id
const ids = {userId:110}

//传入泛型
get<IUserInfo>(userUrl,ids).then({data, status} => {
    if(status == 200) {
        // 数据获取成功
        console.log(data.name) //用户名
        console.log(data.age) //年龄
        console.log(data.gender) //性别
    }
})