Skip to content

HTTP 网络请求

23:52

概述

项目集成了 uView Pro 的 HTTP 请求模块,提供了便捷的网络请求解决方案,包含请求/响应拦截、LoadingToast 提示等功能。

基本配置

HTTP 拦截器配置

src/common/http.interceptor.ts 中配置全局的 HTTP 设置:

typescript
import type { RequestConfig, RequestInterceptor, RequestMeta, RequestOptions } from 'uview-pro'

// 配置 API 基础地址
const baseUrl = 'https://your-api.com'

// 全局请求配置
const httpRequestConfig: RequestConfig = {
  baseUrl,
  header: {
    'content-type': 'application/json',
  },
  timeout: 50000,  // 超时时间(毫秒)
  meta: {
    originalData: true,  // 返回原始数据
    toast: true,         // 显示 toast 提示
    loading: true,       // 显示 loading 动画
  },
}

// 请求/响应拦截器
const httpInterceptor: RequestInterceptor = {
  request: (config: RequestOptions) => {
    // 可以在这里添加 token、自定义 header 等
    if (token) {
      config.header.Authorization = `Bearer ${token}`
    }
    return config
  },
  response: async (response: any) => {
    // 处理响应数据
    return response
  },
}

在 main.ts 中初始化

typescript
import uViewPro, { httpPlugin } from 'uview-pro'
import { httpRequestConfig, httpInterceptor } from '@/common/http.interceptor'

export function createApp() {
  const app = createSSRApp(App)

  // 注册uView-pro
  app.use(uViewPro)

  // 注册http插件
  app.use(httpPlugin, {
    interceptor: httpInterceptor,
    requestConfig: httpRequestConfig
  })

  return { app }
}

基本使用

GET 请求

typescript
import { http } from 'uview-pro'

// 发起 GET 请求
const fetchUserList = async () => {
  try {
    const res = await http.get('/api/users')
    console.log('用户列表:', res)
  } catch (error) {
    console.error('请求失败:', error)
  }
}

POST 请求

typescript
import { http } from 'uview-pro'

const createUser = async () => {
  try {
    const res = await http.post('/api/users', {
      name: '张三',
      email: 'zhangsan@example.com'
    })
    console.log('创建成功:', res)
  } catch (error) {
    console.error('创建失败:', error)
  }
}

PUT/PATCH 请求

typescript
import { http } from 'uview-pro'

const updateUser = async (id: string) => {
  try {
    const res = await http.put(`/api/users/${id}`, {
      name: '李四',
      email: 'lisi@example.com'
    })
    console.log('更新成功:', res)
  } catch (error) {
    console.error('更新失败:', error)
  }
}

DELETE 请求

typescript
import { http } from 'uview-pro'

const deleteUser = async (id: string) => {
  try {
    const res = await http.delete(`/api/users/${id}`)
    console.log('删除成功:', res)
  } catch (error) {
    console.error('删除失败:', error)
  }
}

高级用法

自定义请求配置

可以在单个请求中覆盖全局配置:

typescript
import { http } from 'uview-pro'

// 关闭 Loading 提示
const fetchData = async () => {
  const res = await http.get('/api/data', {}, {
    meta: {
      loading: false,  // 不显示 loading
      toast: true      // 显示 toast
    }
  })
}

// 自定义超时
const slowRequest = async () => {
  const res = await http.get('/api/slow-api', {}, {
    timeout: 30000  // 30 秒超时
  })
}

// 自定义 Header
const sendToken = async (token: string) => {
  const res = await http.get('/api/protected', {}, {
    header: {
      'Authorization': `Bearer ${token}`
    }
  })
}

使用 Composable 管理请求

创建 src/api/useUserApi.ts

typescript
import { http } from 'uview-pro'
import { ref } from 'vue'

export function useUserApi() {
  const users = ref([])
  const loading = ref(false)

  // 获取用户列表
  const fetchUsers = async () => {
    loading.value = true
    try {
      const res = await http.get<any>('/api/users')
      users.value = res.data
    }
    finally {
      loading.value = false
    }
  }

  // 创建用户
  const createUser = async (data: any) => {
    return await http.post('/api/users', data)
  }

  // 更新用户
  const updateUser = async (id: string, data: any) => {
    return await http.put(`/api/users/${id}`, data)
  }

  // 删除用户
  const deleteUser = async (id: string) => {
    return await http.delete(`/api/users/${id}`)
  }

  return {
    users,
    loading,
    fetchUsers,
    createUser,
    updateUser,
    deleteUser,
  }
}

在组件中使用:

vue
<script setup lang="ts">
import { useUserApi } from '@/api/useUserApi'

const { users, loading, fetchUsers } = useUserApi()

onMounted(() => {
  fetchUsers()
})
</script>

<template>
  <view v-if="loading" class="loading">加载中...</view>
  <view v-else class="user-list">
    <view v-for="user in users" :key="user.id" class="user-item">
      {{ user.name }}
    </view>
  </view>
</template>

文件上传

typescript
import { http } from 'uview-pro'

const uploadFile = async (filePath: string) => {
  try {
    const res = await http.upload('/api/upload', {
      filePath,
      name: 'file'
    })
    console.log('上传成功:', res)
  } catch (error) {
    console.error('上传失败:', error)
  }
}

并发请求

typescript
import { http } from 'uview-pro'

// 发起多个并发请求
const fetchDashboard = async () => {
  try {
    const [users, posts, comments] = await Promise.all([
      http.get('/api/users'),
      http.get('/api/posts'),
      http.get('/api/comments')
    ])
    console.log('仪表盘数据:', { users, posts, comments })
  } catch (error) {
    console.error('数据加载失败:', error)
  }
}

错误处理

全局错误处理

在 HTTP 拦截器中处理常见错误:

typescript
import { $u } from 'uview-pro'

const httpInterceptor: RequestInterceptor = {
  response: async (response: any) => {
    const { statusCode, data: rawData, errMsg } = response
    
    // 处理网络错误
    if (errMsg?.includes('Failed to connect')) {
      showToast('网络连接失败', 'error')
      throw new Error('网络错误')
    }
    
    // 处理 HTTP 状态码
    if (statusCode === 401) {
      // 处理未授权(可能需要重新登录)
      uni.redirectTo({ url: '/pages/login/login' })
    }
    
    if (statusCode === 403) {
      $u.toast('没有权限访问', 'error')
    }
    
    if (statusCode >= 500) {
      $u.toast('服务器错误,请稍后重试', 'error')
    }
    
    return rawData
  }
}

组件级错误处理

typescript
import { http } from 'uview-pro'

const fetchData = async () => {
  try {
    const res = await http.get('/api/data')
    // 处理成功
  } catch (error) {
    // 处理错误
    if (error instanceof NetworkError) {
      console.error('网络错误:', error.message)
    } else if (error instanceof TimeoutError) {
      console.error('请求超时:', error.message)
    } else {
      console.error('未知错误:', error)
    }
  }
}

常见场景

带认证的 API 请求

typescript
import { useUserStore } from '@/stores/user'

const httpInterceptor: RequestInterceptor = {
  request: (config: RequestOptions) => {
    const userStore = useUserStore()
    if (userStore.token) {
      config.header.Authorization = `Bearer ${userStore.token}`
    }
    return config
  }
}

调试技巧

查看完整的请求和响应

typescript
const httpInterceptor: RequestInterceptor = {
  request: (config: RequestOptions) => {
    if (__DEV__) {
      console.log('📤 请求:', config.url, config.data)
    }
    return config
  },
  response: async (response: any) => {
    if (__DEV__) {
      console.log('📥 响应:', response.config.url, response.data)
    }
    return response
  }
}

使用网络监控工具

在真机调试时,可以使用:

  • Android:使用 Charles 或 Fiddler 进行 HTTP 抓包
  • iOS:使用 Charles 或 Proxy 进行 HTTP 抓包

最佳实践

  1. 分离 API 层 - 为不同的业务模块创建对应的 API 文件
  2. 使用 TypeScript - 定义 API 响应类型,获得更好的类型提示
  3. 错误处理 - 在所有请求中都添加 try-catch 处理
  4. Loading 提示 - 对长时间的请求显示 Loading 动画
  5. 请求取消 - 在组件卸载时取消未完成的请求
  6. 请求超时 - 为不同的请求设置合理的超时时间
  7. 缓存策略 - 对频繁请求的数据进行缓存

相关文档