laravel封装请求带状态加载token
xuexi 2025-03-12 17:11:43 发表在:PHP 查看数:220

完整代码:utils/request.js

// utils/request.js

// 基础配置
const BASE_URL = 'https://your-api.com/api' // 替换为你的接口地址

// 请求封装类
class HttpRequest {
  constructor() {
    this.config = {
      baseUrl: BASE_URL,
      header: {
        'Content-Type': 'application/json'
      }
    }
    this.queue = {} // 请求队列(用于防止重复提交)
  }

  // 核心请求方法
  async request(options) {
    // 合并配置
    const mergedOptions = {
      ...this.config,
      ...options,
      url: this.config.baseUrl + options.url
    }

    // 显示加载状态(可配置)
    if (mergedOptions.showLoading !== false) {
      uni.showLoading({
        title: '加载中...',
        mask: true
      })
    }

    // 防止重复提交
    const requestKey = `${mergedOptions.url}_${JSON.stringify(mergedOptions.data)}`
    if (this.queue[requestKey]) {
      return Promise.reject(new Error('重复请求已被拦截'))
    }
    this.queue[requestKey] = true

    // 添加 Token
    const token = uni.getStorageSync('token')
    if (token) {
      mergedOptions.header = {
        ...mergedOptions.header,
        Authorization: `Bearer ${token}`
      }
    }

    return new Promise((resolve, reject) => {
      uni.request({
        ...mergedOptions,
        success: (res) => {
          // 隐藏加载状态
          if (mergedOptions.showLoading !== false) {
            uni.hideLoading()
          }

          // 移除请求队列标记
          delete this.queue[requestKey]

          // 处理 HTTP 状态码
          if (res.statusCode !== 200) {
            return this.handleHttpError(res.statusCode, res.data)
          }

          // 处理业务逻辑(假设接口返回格式为 { code: 200, data: {}, message: 'success' })
          if (res.data.code !== 200) {
            return this.handleBusinessError(res.data.code, res.data.message)
          }

          // 返回数据
          resolve(res.data.data)
        },
        fail: (err) => {
          // 隐藏加载状态
          if (mergedOptions.showLoading !== false) {
            uni.hideLoading()
          }

          // 移除请求队列标记
          delete this.queue[requestKey]

          // 处理网络错误
          reject(new Error('网络请求失败'))
          uni.showToast({
            title: '网络请求失败',
            icon: 'none'
          })
        }
      })
    })
  }

  // 处理 HTTP 错误
  handleHttpError(statusCode, data) {
    const errorMap = {
      400: '请求参数错误',
      401: () => {
        uni.removeStorageSync('token')
        uni.reLaunch({ url: '/pages/login/login' })
        return '登录已过期,请重新登录'
      },
      403: '没有操作权限',
      404: '资源不存在',
      500: '服务器错误',
      502: '网关错误'
    }

    const errorHandler = errorMap[statusCode] || (() => `网络请求错误 (${statusCode})`)
    const errorMessage = typeof errorHandler === 'function' ? errorHandler() : errorHandler

    uni.showToast({
      title: errorMessage,
      icon: 'none'
    })

    return Promise.reject(new Error(errorMessage))
  }

  // 处理业务错误
  handleBusinessError(code, message) {
    const errorMessages = {
      1001: '参数校验失败',
      1002: '操作过于频繁',
      // ...其他业务错误码
    }

    const errorMessage = errorMessages[code] || message || '操作失败'

    uni.showToast({
      title: errorMessage,
      icon: 'none'
    })

    return Promise.reject(new Error(errorMessage))
  }

  // 快捷方法
  get(url, params, options) {
    return this.request({
      method: 'GET',
      url,
      data: params,
      ...options
    })
  }

  post(url, data, options) {
    return this.request({
      method: 'POST',
      url,
      data,
      ...options
    })
  }

  put(url, data, options) {
    return this.request({
      method: 'PUT',
      url,
      data,
      ...options
    })
  }

  delete(url, data, options) {
    return this.request({
      method: 'DELETE',
      url,
      data,
      ...options
    })
  }
}

// 创建实例
const http = new HttpRequest()

// 导出实例
export default http

使用示例

  1. 在 Vue 组件中使用
    <template>
    <view>
     <button @click="fetchData">获取数据</button>
    </view>
    </template>
<script>
import http from '@/utils/request'

export default {
  methods: {
    async fetchData() {
      try {
        const data = await http.get('/user/info', { id: 1 })
        console.log('获取数据成功:', data)
      } catch (err) {
        console.error('请求失败:', err)
      }
    }
  }
}
</script>

2. 在页面中使用

import http from '@/utils/request'

export default {
  onLoad() {
    this.loadData()
  },
  methods: {
    async loadData() {
      try {
        const result = await http.post('/submit', { name: 'test' })
        console.log('提交成功:', result)
      } catch (err) {
        console.error('提交失败:', err)
      }
    }
  }
}

主要功能说明 自动携带 Token:

从本地存储中读取 token,并自动添加到请求头中。

如果 Token 过期(401 状态码),会自动跳转到登录页。

状态拦截:

统一处理 HTTP 状态码(如 400、401、403、500 等)。

支持自定义业务错误码处理。

防止重复提交:

相同的请求在未完成前会被拦截,避免重复提交。

加载状态:

默认显示全局 Loading,支持单个请求禁用 Loading。

错误提示:

网络错误、HTTP 错误、业务错误都会通过 uni.showToast 提示用户。 配置说明 修改基础地址:

将 BASE_URL 替换为你的接口地址。

Token 存储:

登录成功后,调用以下代码存储 Token:

uni.setStorageSync('token', 'your_token_here')

禁用 Loading:

如果某个请求不需要显示 Loading,可以传入 showLoading: false:

http.get('/user/info', { id: 1 }, { showLoading: false })
最近访问时间:2025-05-01 02:12:48
知识库:340条鸣谢:TAY  备案号:蜀ICP备2024090044号