甜倩 發表於 2026-4-17 11:24:00

uni.request 二次封装分享

<h1 data-id="heading-0">🧑‍💻 写在开头</h1>
<p>点赞 + 收藏 === 学会🤣🤣🤣</p>
<div>
<div>
<h2 data-id="heading-0"><strong>基于uni.request api进行二次封装</strong></h2>
<h3 data-id="heading-1">核心功能</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" checked="checked" disabled="disabled"> 响应内容格式和请求参数格式类型定义</li>
<li class="task-list-item"><input type="checkbox" checked="checked" disabled="disabled"> 请求拦截器与响应拦截器配置</li>
<li class="task-list-item"><input type="checkbox" checked="checked" disabled="disabled"> 设置请求头和params参数处理</li>
<li class="task-list-item"><input type="checkbox" checked="checked" disabled="disabled"> 加载提示与自定义提示文本</li>
<li class="task-list-item"><input type="checkbox" checked="checked" disabled="disabled"> 错误统一处理</li>
<li class="task-list-item"><input type="checkbox" checked="checked" disabled="disabled"> 接口缓存</li>
<li class="task-list-item"><input type="checkbox" disabled="disabled"> 取消请求功能</li>
<li class="task-list-item"><input type="checkbox" disabled="disabled"> 失败自动重试机制</li>
<li class="task-list-item"><input type="checkbox" disabled="disabled"> 并发请求控制</li>
</ul>
<h3 data-id="heading-2">核心代码</h3>
</div>
</div>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">// 响应内容格式
export interface InResult&lt;T&gt; {
code: number | string
message: string
success: boolean
# data: T
}
// 请求参数格式
interface RequestOptions {
baseURL?: string
url: string
method?: 'GET' | 'POST' | 'PUT' | 'DELETE'
data?: Record&lt;string, any&gt;
params?: Record&lt;string, any&gt;
header?: Record&lt;string, string&gt;
loading?: boolean // 是否显示加载中提示
loadingText?: string // 加载中提示文本
removeToken?: boolean // 是否移除token
cache?: boolean // 是否缓存响应结果
returnResponse?: boolean // 直接返回响应
}

// 设置请求头
function setRequestHeaders(url: string) {
const LOGIN_URL = '/auth/oauth2/token'
if (url.includes(LOGIN_URL)) {
    return { Authorization: `Basic Z2VveHNwYWNlOmdlb3hzcGFjZQ==` }
}
const token = uni.getStorageSync('token')
if (token) {
    return { Authorization: `Bearer ${token}` }
}
return {} as Record&lt;string, string&gt;
}
// 请求和响应拦截器
function requestAndResponseInterceptor() {
uni.addInterceptor('request', {
    // 调用前置拦截器
    invoke(options: RequestOptions) {
      if (options.loading) {
      uni.showLoading({
          title: options.loadingText || '加载中...',
          mask: true,
      })
      }

      options.header = {
      ...options.header,
      ...setRequestHeaders(options.url),
      }

      // 移除token
      if (options.removeToken) {
      delete options.header.Authorization
      }

      // 处理params 参数
      if (options.params) {
      const urlPrams: string[] = []
      Object.keys(options.params).forEach((key) =&gt; {
          urlPrams.push(`${key}=${options.params!}`)
      })
      if (options.url.includes('?')) {
          options.url += urlPrams.join('&amp;')
      }
      else {
          options.url += `?${urlPrams.join('&amp;')}`
      }
      }
      return options
    },

    // 调用后置拦截器
    success(res) {
      return res
    },
    fail(err) {
      uni.showToast({
      title: '网络请求失败',
      icon: 'none',
      })
      return Promise.reject(err)
    },

    complete(option) {
      console.log('option.errMsg', option.errMsg)
      setTimeout(() =&gt; {
      uni.hideLoading()
      }, 15000)
    },
})
}

// 调用请求拦截器和响应拦截器
requestAndResponseInterceptor()

const cacheMap = new Map&lt;string, any&gt;()
// 封装网络请求
export async function request(options: RequestOptions): Promise&lt;any&gt; {
const { baseURL, url, header = {}, cache, returnResponse } = options
// 合并配置
const config = {
    ...options,
    url: url.startsWith('http') ? options.url : baseURL + options.url,
    header: {
      'Content-Type': 'application/json',
      ...header, // 允许自定义header
    },
    timeout: 10000, // 超时时间(ms)
}

if (cache) {
    if (cacheMap.has(url)) {
      return cacheMap.get(url)
    }
}

try {
    const response = await uni.request(config)

    if (options.loading) {
      uni.hideLoading()
    }
    // 响应拦截器
    if (response.statusCode === 200) {
      const data = returnResponse ? response : response.data
      if (cache) {
      cacheMap.set(url, data)
      }

      // @ts-expect-error 判断异常
      if (response.data.code !== '20000') {
      // @ts-expect-error 判断异常
      toast(response.data.msg, {
          icon: 'fail',
      })
      }

      return data
    }
    if (response.statusCode === 401) {
      toast('登录已过期,请重新登录!', {}, () =&gt; {
      uni.redirectTo({
          url: '/user/login/index',
      })
      })
    }
    else {
      toast('系统服务异常!')
    }
}
catch (error) {
    return Promise.reject(error)
}
}</pre>
</div>
<h3 data-id="heading-3">toast 封装代码</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">export function toast(title: string, options?: { duration?: number, icon?: 'success' | 'loading' | 'error' | 'none' | 'fail' | 'exception', mask?: boolean }, callback?: () =&gt; void) {
const { mask = true, duration = 1000, icon = 'none' } = options || {}

if (title &amp;&amp; title.length &gt; 14) {// 当作字符长度&gt;14时使用showModal展示
    uni.showModal({
      content: title,
      showCancel: false,
      success() {
      if (callback &amp;&amp; typeof callback === 'function') {
          const timer = setTimeout(() =&gt; {
            callback()
            clearTimeout(timer)
          }, duration)
      }
      },
    })
}
else {
    uni.showToast({
      title,
      message: title,
      icon,
      mask,
      duration,
      success() {
      if (callback &amp;&amp; typeof callback === 'function') {
          const timer = setTimeout(() =&gt; {
            callback()
            clearTimeout(timer)
          }, duration)
      }
      },
    })
}
}</pre>
</div>
<h3 data-id="heading-4">使用示例</h3>
<div class="cnblogs_Highlighter">
<pre class="brush:csharp;gutter:true;">import { type InResult, request } from '@/utils/request'

export interface IUser {
    id: string,
    name: string,
    age?: number
}

export function getUserList(data: any): Promise&lt;InResult&lt;{ records: Array&lt;IUser&gt;, total: number }&gt;&gt; {
return request({
    baseURL,
    url: '/user/page',
    method: 'POST',
    params: data,
    loading: true,
})
}</pre>
</div>
<div>
<h3 id="tid-D8HBxE">如果对您有所帮助,欢迎您点个关注,我会定时更新技术文档,大家一起讨论学习,一起进步。</h3>
</div>
<p><em><img src="https://img2024.cnblogs.com/blog/2149129/202501/2149129-20250122165814748-630765389.png" alt="" loading="lazy"></em></p><br><br>
来源:https://www.cnblogs.com/smileZAZ/p/19882187
頁: [1]
查看完整版本: uni.request 二次封装分享