Uniapp Ts + Vue3.2 封装网络请求

1,054 阅读2分钟

1. 定义 .env.development

  • 方便于全局引入变量
  • 对.env , .env.[不同环境] 进行环境隔离
VITE_APP_API=https://xxx
VITE_APP_API_TIMEOUT=10 # x * 1000 = x seconds

2. 工具类(包含拦截器,类型接口)

  • 封装 uniapp.request 简化 http请求,
  • Ts 泛型化
  • 全局业务状态码捕获
// 1.引入Env变量
const API = import.meta.env.VITE_APP_API;
const API_TIMEOUT = import.meta.env.VITE_APP_API_TIMEOUT;

// 2.uniapp 拦截器
uni.addInterceptor('request', {
  invoke(options) {
   // 请求前对请求头操作 , 如添加校验请求头 Authorization
  },
  success(response) {
    // 请求成功操作
  },
  fail(err) {
   // 请求网络异常操作
    console.log('interceptor-fail', err);
  },
  complete(res) {
    // console.log('interceptor-complete', res);
  },
});

// 3. 通用返回接口 
// 可放 types/global.d.ts [declare 声明]。这里方便展示
interface Response<T = unknown> {
  code: number;
  msg: string;
  result: T;
}

/**
 * 默认状态码
 */
const STATUS_CODE = {
  SUCCESS: 200,
  FAIL: 400,
};

/**
 * 对 uni.request 进行工具封装
 *
 * @param option {{@link UniNamespace.RequestOptions}}
 */
const useHttp = <T>(option: UniNamespace.RequestOptions) => {
  return new Promise<Response<T>>((resolve, reject) => {
    uni.request({
      ...option,
      success(res) {
        // 业务判断成功
        const result = res.data as Response<T>;
        resolve(result);
        
        // ....省略
        
        // 业务判断失败
        reject(res);
      },
      fail(err) {
        // 请求网络异常操作
        reject(err);
      },
    });
  });
};

// GET 请求封装, Omit 排除 method 类型
const useHttpGet = <T>(option: Omit<UniNamespace.RequestOptions, 'method'>) => {
  return useHttp<T>({
    ...option,
    method: 'GET',
  });
};

// POST 请求封装, Omit 排除 method 类型
const useHttpPost = <T>(
  option: Omit<UniNamespace.RequestOptions, 'method'>
) => {
  return useHttp<T>({
    ...option,
    method: 'POST',
  });
};

export { useHttp, useHttpGet, useHttpPost, STATUS_CODE };
export type { Response };

3. Api函数

  • 简化网络请求流程
import { useHttp } from '@/utils/httpClient';

/**
 * 获取用户信息
 *
 * @param username 用户名
 * @return Promise<Response<string>>
 */
export const getUserDataApi = (username: string) => {
  return useHttpGet<string>({
    url: '/user',
    data: {
      username,
    },
  });
};

引入 vue-request 三方网络请求库

官网: [cn.attojs.org/guide/intro…]

npm install vue-request

使用案例

进一步简化数据的获取,需根据 Response 接口定义

import type { Ref } from 'vue';
import { computed } from 'vue';
import type { Response } from '@/utils/httpClient';

type R<T> = Ref<Response<T> | undefined>;

/**
 * 简化获取请求列表数据的逻辑
 *
 * @param response 响应数据
 * @param defaultVal 默认值
 * @return 业务数据 response?.value?.data
 */
export const useDataList = <T>(response: R<T>, defaultVal = <T>[]) => {
  return computed<T>(() => {
    return response?.value?.result || defaultVal;
  });
};

/**
 * 简化获取请求数据的逻辑
 *
 * @param response 响应数据
 * @param defaultVal 默认值
 * @return 业务数据 response?.value?.data
 */
export const useData = <T>(response: R<T>, defaultVal = <T>{}) => {
  return computed<T>(() => {
    return response?.value?.result || defaultVal;
  });
};

Vue3.2 中使用

import { getUserDataApi } from '@/services/api/user';
import { useData } from '@/hooks/useResponse';

// 默认 manual: false, 自动请求
<script lang="ts" setup>
  const { data: hotRes, loading } = useRequest(getUserDataApi);
  const userData = useData(hotRes); // ts -> userData: string
</script>

<template>
  <view>
    是否加载中: {{ loading }}
    用户的数据: {{ userData }}
  </view>
</template>

<style lang="scss"></style>