npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@xiao-ying/miniapp-request

v1.1.0

Published

Axios-like request wrapper built on @xiao-ying/miniapp-sdk with middleware and shared headers

Readme

@xiao-ying/miniapp-request

基于 @xiao-ying/miniapp-sdk 的 axios 风格请求层,统一封装 request / uploadFile / downloadFile,支持中间件、异步/静态共享请求头,以及可配置的 HTTP 状态码抛错策略。

  • SDK 行为:xy.request 等始终返回 { data, statusCode, headers },不因 4xx/5xx 抛错。
  • 本封装默认行为:statusCode < 400 视为成功,否则抛出 HTTP_ERROR_xxx;可通过 validateStatusCode 改为不抛或自定义规则。

安装

pnpm add @xiao-ying/miniapp-request

快速开始

import { createXyRequestClient } from '@xiao-ying/miniapp-request'

const client = createXyRequestClient({
  baseURL: 'https://api.example.com',
  // 共享请求头可异步获取
  headers: async ({ action }) => ({
    Authorization: `Bearer ${await getToken()}`,
    'X-Action': action
  })
})

// 中间件:打印耗时
client.use(async (ctx, next) => {
  const startedAt = Date.now()
  const result = await next()
  console.info('[xy-request]', ctx.request.url, result.kind, `${Date.now() - startedAt}ms`)
  return result
})

// 请求(GET / POST / PUT / PATCH / DELETE)
const res = await client.post('/foo', { hello: 'world' }, { params: { lang: 'zh-CN' } })
console.log(res.data)

// 上传
await client.uploadFile({
  url: '/upload',
  method: 'POST',
  fileKey: 'file',
  filePath: '/tmp/demo.jpg'
})

// 下载
const download = await client.downloadFile({ url: '/file.zip' })
console.log(download.filePath)

API 总览

  • 工厂:createXyRequestClient<TExtra extends Record<string, any> = Record<string, any>>(options?: RequestClientOptions<TExtra>): XyRequestClient<TExtra>
  • 实例方法:
    • use(middleware):注册中间件(链式)
    • setSharedHeaders(source):更新共享请求头(静态或异步函数)
    • request(config),以及 get / delete / post / put / patch
    • uploadFile(config)downloadFile(config)
    • extend(partialOptions):继承当前配置,中间件可追加
  • 关键选项:
    • baseURL:统一前缀(仅对相对路径生效)
    • headers:共享请求头(对象或函数)
    • middlewares:默认中间件数组
    • validateStatusCode?: (code: number) => boolean:返回 true 视为成功,不抛错;默认 code < 400

共享请求头

  • 支持静态对象:{ Authorization: 'Bearer xxx' }
  • 支持异步函数:({ action, url }) => Promise<Headers>
  • 注入顺序:共享头 -> 客户端中间件 -> 局部中间件 -> 最终请求
  • 在任意中间件中可调用 ctx.mergeHeaders() 追加/覆盖

client.use 用法示例

中间件签名:(ctx, next) => Promise<RequestResult>,其中 ctx.request 已包含 kind/url/headers/...,以及可选的 extra 元数据,next() 进入后续中间件或最终请求。

请求/响应日志

client.use(async (ctx, next) => {
  console.debug('➡️', ctx.request.method ?? 'GET', ctx.request.url)
  const res = await next()
  console.debug('⬅️', res.kind, res.response.statusCode)
  return res
})

动态鉴权头(可与共享头并用)

client.use(async (ctx, next) => {
  const token = await getTokenMaybeRefresh()
  if (token) ctx.mergeHeaders({ Authorization: `Bearer ${token}` })
  return next()
})

错误提示:链内不抛、链外抛(默认)

默认 validateStatusCode = (c) => c < 400await next() 不会因 4xx/5xx 抛错,方便在中间件里直接读取响应做 toast;中间件链结束后,client.post() 等会按校验结果在返回前抛出 HTTP_ERROR_xxx

client.use(async (ctx, next) => {
  const res = await next() // 不需要 try/catch
  if (res.response.statusCode >= 400) {
    xy.showToast({ title: '请求失败', subtitle: res.response.data?.message, type: 'error' })
  }
  return res
})

// 调用处依然会抛出 HTTP_ERROR_xxx
await client.post('/foo', data) // 4xx/5xx 将在这里抛出

错误提示:完全不抛

创建客户端时放宽校验,4xx/5xx 既不会在 next() 抛,也不会在 client.post() 抛:

const client = createXyRequestClient({
  validateStatusCode: () => true // 永远不抛错
})

client.use(async (ctx, next) => {
  const res = await next()
  if (res.response.statusCode >= 400) {
    xy.showToast({ title: '请求失败', subtitle: res.response.data?.message, type: 'error' })
  }
  return res
})

短路 / Mock(不触网)

client.use(async (ctx, next) => {
  if (ctx.request.url.startsWith('/mock/')) {
    return { kind: 'request', response: { data: { ok: true }, statusCode: 200, headers: {} } }
  }
  return next()
})

局部中间件

client.post('/foo', data, {
  middlewares: [async (ctx, next) => {
    ctx.mergeHeaders({ 'X-Trace': crypto.randomUUID() })
    return next()
  }]
})

extra 元数据(可类型化)

extra 仅用于中间件链路的上下文传递,不会透传到底层请求。

const client = createXyRequestClient<{ traceId: string }>()

client.use(async (ctx, next) => {
  console.log(ctx.request.extra?.traceId)
  return next()
})

实例复用

const authed = client.extend({
  headers: { 'X-Env': 'prod' },
  validateStatusCode: (code) => code < 500 // 允许 4xx 走正常分支
})

与全局 xy 实例

默认使用全局 xy(由宿主或 @xiao-ying/miniapp-sdk 初始化)。浏览器环境请同时引入 @xiao-ying/miniapp-sdk-browser 以完成注入。如需自定义 SDK 实例,可在 createXyRequestClient({ sdk })client.extend({ sdk }) 中显式传入。

WebSocket

miniapp-request 提供 XyWsClient 作为 xy.ws 的同步封装,支持中间件链与多层代理嵌套。

创建客户端

import { createXyWsClient } from '@xiao-ying/miniapp-request'

const wsClient = createXyWsClient({
  baseURL: 'https://ws.example.com'
})

const ws = wsClient.connect({ url: '/socket' })
ws.onOpen = () => console.info('open')
ws.onMessage = (evt) => console.info('message', evt.data)

多层代理(中间件)

import { createXyWsClient } from '@xiao-ying/miniapp-request'
import {
  createWsProxyMiddleware,
  createWsPathUrlBuilder
} from '@xiao-ying/miniapp-request-proxy'

const wsClient = createXyWsClient()
wsClient.use(createWsProxyMiddleware({
  buildUrl: createWsPathUrlBuilder({ prefix: 'https://inner-proxy.com/ws' })
}))
wsClient.use(createWsProxyMiddleware({
  buildUrl: createWsPathUrlBuilder({ prefix: import.meta.env.VITE_XY_PROXY_PREFIX ?? '/dev-proxy/' })
}))

const ws = wsClient.connect({ url: 'wss://ws.example.com/echo' })

中间件观察示例

wsClient.use((ctx, next) => {
  const socket = next()
  const originalSend = socket.send.bind(socket)
  socket.send = (data) => {
    console.info('[ws send]', data)
    originalSend(data)
  }
  socket.addEventListener('message', (evt) => {
    console.info('[ws message]', evt.data)
  })
  return socket
})

说明:

  • connect 与中间件均为同步调用,若需异步 token 请提前获取后再连接。
  • 代理仅改写 URL,不注入请求头。
  • WS 代理中间件来自 @xiao-ying/miniapp-request-proxy