更新记录

1.0.4(2021-08-24)

1、插件改为函数式 2、useRequest 的Bug 修复

1.0.1(2021-07-10)

中间件由 class 改为 function;中间件支持的参数,支持请求时传入

0.4.7(2021-06-29)

1、fetch 支持 cancelToken 取消请求 2、fetch 支持文件下载进度查看 3、http method 改为大写

查看更多

平台兼容性

Vue2 Vue3
App 快应用 微信小程序 支付宝小程序 百度小程序 字节小程序 QQ小程序
HBuilderX 3.1.10 app-vue app-nvue
钉钉小程序 快手小程序 飞书小程序 京东小程序
× × × ×
H5-Safari Android Browser 微信浏览器(Android) QQ浏览器(Android) Chrome IE Edge Firefox PC-Safari

@prequest/miniprogram

小程序请求库.

安装

npm install @prequest/miniprogram

DEMO

demo 包含了下面提到的所有功能,感兴趣的可以拉下来看一下。

文档地址

这篇文档可能不会及时更新,使用方式以网站为准。

https://pre-quest.vercel.app/#/miniprogram

文章

原生请求

首先,看一下原生请求的 demo

const requestInstance = uni.request({
  url: 'http://localhost:3000/api',
  method: 'POST',
  data: {
    x: '',
  },
  header: {
    'content-type': 'application/json',
  },
  success(res) {
    console.log(res.data)
  },
})

requestInstance.abort()

基本使用

import { create, PreQuest } from '@prequest/miniprogram'

const prequest = create(uni.request)

prequest('http://localhost:3000/api').then(res => console.log(res))
prequest.get('http://localhost:3000/api').then(res => console.log(res))

高级使用

全局配置

import { create, PreQuest } from '@prequest/miniprogram'

// global config
PreQuest.defaults.baseURL = 'http://localhost:3000'

// global middleware
PreQuest.use(async (ctx, next) => {
  // modify request params
  console.log(ctx.request)
  await next()
  // handle response error or modify response data
  console.log(ctx.response)
})

实例配置

// instance config options
const opt = { baseURL: 'http://localhost:3001' }

// pass in native request core, so you can use this library in different miniprogram platform.
const instance = create(uni.request, opt)

// instance middleware
instance.use(async (ctx, next) => {
  ctx.request.path = '/prefix' + ctx.request.path
  await next()
  ctx.response = JSON.parse(ctx.response)
})

// request
instance.request({ path: '/api' })

// instance.request shortcut
instance('/api')

// request by alias
instance.get('/api')

拦截器

中间件模型可以很好的完成修改请求和响应的工作。如果你想像 axios 一样使用拦截器,PreQuest 也提供了相应的方案

import { PreQuest, create } from '@prequest/miniprogram'
import InterceptorMiddleware from '@prequest/interceptor'

// create Interceptor instance
const interceptor = new InterceptorMiddleware()

// mount global interceptor middleware
PreQuest.use(interceptor.run)

// or you can mount it to prequest instance
const prequest = create(uni.request)
prequest.use(interceptor.run)

// use
interceptor.request.use(
  requestOpt => modify(requestOpt),
  err => handleErr(err)
)

原生请求实例

怎样获得原生请求实例?

import { PreQuest, create } from '@prequest/miniprogram'

const instance = create(uni.request)

instance.request({
  path: '/api',
  getNativeRequestInstance(promise) {
    promise.then(nativeRequest => {
      nativeRequest.abort()
    })
  },
})

超时处理

uni 中只支持微信小程序和支付宝小程序设置超时,使用这个中间件,全平台都可以设置超时时间

import TimeoutMiddleware, { TimeoutInject } from '@prequest/timeout'
import { create } from '@prequest/fetch'

const platform = process.env.UNI_PLATFORM

// 统一设置超时时间
const timeoutMiddleware = TimeoutMiddleware({
  timeout: 5000,
  timeoutControl(opt) {
    // 微信小程序、支付宝小程序 timeout 由请求内核进行处理
    if (['mp-alipay', 'mp-weixin'].includes(platform)) return false

    // 其余由中间件处理
    return true
  },
})
prequest.use(timeoutMiddleware)

// 或者针对单一请求进行设置
const prequest = create<TimeoutInject, {}>()
prequest('/api', { timeout: 1000 })

取消请求

可以使用获得原生实例请求的方式取消请求。

此外,还可以使用 cancelToken 来取消请求

方式一:

import { PreQuest, create } from '@prequest/miniprogram'
import CancelToken from '@prequest/cancel-token'

const instance = create(uni.request)

const source = CancelToken.source()

instance.request({
  path: '/api',
  cancelToken: source.token,
})

source.cancel()

方式二:

import { create } from '@prequest/miniprogram'
import CancelToken from '@prequest/cancel-token'

const instance = create(uni.request)

let cancel

instance.request({
  path: '/api',
  cancelToken: new CancelToken(c => (cancel = c)),
})

cancel()

缓存数据

缓存接口数据

import { create, Request, Response } from '@prequest/miniprogram'
import CacheMiddleware from '@prequest/cache'

const cacheMiddleware = CacheMiddleware<Request, Response>({
  ttl: 5000,
  cacheId(opt) {
    const { path, method } = opt
    return `${method}-${path}`
  },
  cacheControl(opt) {
    const { path } = opt
    if(path === '/api') return true
    return false
  },
  cacheKernel() {
    const map = new Map()
    return {
      set: map.set,
      get: map.get,
      clear: map.clear,
      delete: map.delete
    }
  }
})

const instance = create(uni.request)

instance.use(cacheMiddleware)

刷新 Token

静默刷新 token

import { create, Request, Response } from '@prequest/miniprogram'
import Lock from '@prequest/lock'

const prequest = create(uni.request)

// 创建 lock 实例
const lock = new Lock({
  async getValue() {
    return getStorageSync('token')
  },
  async setValue(token) {
    setStorageSync('token', token)
  },
  async clearValue() {
    removeStorageSync('token')
  },
})

// 用 lock 实例创建包裹器
const wrapper = Lock.createLockWrapper(lock)

prequest.use(async (ctx, next) => {
  // 自定义了一个参数 skipToken, 用以放行不需要 token 的接口
  if (ctx.request.skipToken) return next()

  /**
   * wrapper 会将所有请求拦截在这里,直到获取到 token 之后才放行
   * 获取 token 接口由于传入了 skipToken 所以不会
   * */
  const token = await wrapper(() =>
    prequest('/token', { skipToken: true }).then(res => res.data.token)
  )

  ctx.request.header = ctx.request.header || {}
  ctx.request.header['Authorization'] = `bearer ${token}`
  await next()
})

// 同时发起 5 个请求,等到 token 拿到后,才会执行
prequest('/api', { params: { a: 1 } })
prequest('/api', { params: { a: 2 } })
prequest('/api', { params: { a: 3 } })
prequest('/api', { params: { a: 4 } })
prequest('/api', { params: { a: 5 } })

这里可以结合错误重试中间件,自动进行接口重新调用,详情参考@prequest/lock

错误重试

import { create, Request, Response } from '@prequest/miniprogram'
import ErrorRetryMiddleware from '@prequest/error-retry'

const prequest = create(uni.request)

const errorRetryMiddleware = ErrorRetryMiddleware<Request, Response>({
  retryCount: 3,
  retryControl(opt, error) {
    const { method, path } = opt

    // 指定的路径不使用错误重试
    if (path === '/api') return false

    // get 请求使用错误重试
    return method === 'GET'
  },
})

prequest.use(errorRetryMiddleware)

prequest.get('/api')

请求配置项

Option Name Type Default Required Meaning Example
path string none Y server interface path /api
method string GET N request method post
baseURL string none N base server interface address 'http://localhost:3000'
getNativeRequestInstance (value: Promise\<NativeInstance>) => void none N get native request instance
cancelToken CancelToken none N cancel a request
timeout number none N request timeout 5000
params object none N url parameters { id: 10}
data object none N the data to be sent as the request body { id: 10}
responseType json | text | arraybuffer |... none N response data type json
header object none N set the request header { token: 'aaaaa'}
dataType json | ... none N returned data format json

注意: 如果你用别名的方式调用一个 HTTP 请求, 就像 instance.get('/api') 这样, 那么你不需要传入 pathmethod 参数到选项中。


此外,你也可以添加一些原生 API 支持的配置项,这部分配置项将会直接传递到原生 API 方法中。

示例:

interface Request {
  enableHttp2?: boolean
  enableCache?: boolean
}

interface Response {
  header: any
  cookies: string[]
  profile: any
}

const instance = create<Request, Response>(uni.request, {
  baseURL: 'http://localhost:3000'
  enableHttp2: true // You can get intelliSense here
})

// You can get intelliSense here
instance.use(async (ctx, next) => {
  ctx.request.enableHttp2
  await next()
  ctx.response.header
})

注意

在 uni 中使用,需要在 vue.config.js 文件中,配置编译 @prequest

module.exports = {
  transpileDependencies: [/@prequest/],
}

隐私、权限声明

1. 本插件需要申请的系统权限列表:

2. 本插件采集的数据、发送的服务器地址、以及数据用途说明:

插件不采集任何数据

3. 本插件是否包含广告,如包含需详细说明广告表达方式、展示频率:

许可协议

MIT协议

使用中有什么不明白的地方,就向插件作者提问吧~ 我要提问