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

@uni-helper/uni-network

v1.0.1

Published

为 uni-app 打造的基于 Promise 的 HTTP 客户端

Readme

@uni-helper/uni-network

为 uni-app 打造的基于 Promise 的 HTTP 客户端。要求 node>=18。

VitePress 在线文档

不想看文档?直接问 AI 🤖

请考虑持续赞助以维持该项目的持续健康发展,非常感谢!🙏

指南

介绍

@uni-helper/uni-network 是一个为 uni-app 打造的 基于 Promise 的 HTTP 客户端。

@uni-helper/uni-network 灵感和代码绝大部分源于 [email protected],功能包括:

起步

@uni-helper/uni-network 要求你使用 node>=18。建议你使用 Node.js 的 LTS 版本。

  • npm

    npm install @uni-helper/uni-network
  • yarn

    yarn add @uni-helper/uni-network

    如果你正在使用 yarn v2+,请参考 文档 设置 nodeLinker 为 node_modules。

  • pnpm

    pnpm add @uni-helper/uni-network

    如果你正在使用 pnpm,请参考 文档 设置 shamefully-hoist 为 true。

目前不支持 uni_modules,也没有人力、精力和时间支持 uni_modules,但欢迎 PR 贡献!🫡

基本用例

GET 请求

import { un } from "@uni-helper/uni-network";

// 请求特定 ID 的用户数据
un.get("/user?ID=12345")
  .then((response) => {
    // 处理响应
    console.log("response", response);
  })
  .catch((error) => {
    // 处理错误
    console.log("error", error);
  })
  .finally(() => {
    // 总是会执行
  });

// 上述请求和以下等同
un.get("/user", {
  params: {
    ID: "12345",
  },
})
  .then((response) => {
    console.log("response", response);
  })
  .catch((error) => {
    console.log("error", error);
  })
  .finally(() => {
    // 总是会执行
  });

un 是 uni 和 network 的首字母缩写。如果你不习惯这个名称,你可以在导入时自行调整,比如使用 uniNetwork:import { un as uniNetwork } from '@uni-helper/uni-network';。

使用 async/await 的 GET 请求

import { un } from "@uni-helper/uni-network";

async function getUser() {
  try {
    const response = await un.get("/user?ID=12345");
    console.log(response);
  } catch (error) {
    console.error(error);
  }
}

POST 请求

import { un } from "@uni-helper/uni-network";

un.post("/user", {
  firstName: "Fred",
  lastName: "Flintstone",
})
  .then(function (response) {
    console.log(response);
  })
  .catch(function (error) {
    console.log(error);
  })
  .finally(() => {});

并发请求

import { un } from "@uni-helper/uni-network";

function getUserAccount() {
  return un.get("/user/12345");
}

function getUserPermissions() {
  return un.get("/user/12345/permissions");
}

Promise.all([getUserAccount(), getUserPermissions()]).then((responses) => {
  const userAccount = responses[0];
  const userPermissions = responses[1];
});

基本用例应该能让你初步上手 @uni-helper/uni-network。你可以动手尝试一下,也可以继续往下阅读。

API

API

可以直接向导入的 un 传递相关配置来发起请求。

un(config)

import { un } from "@uni-helper/uni-network";

// 发起 POST 请求
un({
  method: "post",
  url: "/user/12345",
  data: {
    firstName: "Fred",
    lastName: "Flintstone",
  },
});

un(url[, config])

import { un } from "@uni-helper/uni-network";

// 发起 GET 请求(默认请求方法)
un("/user/12345");

请求别名

为了方便起见,已经为所有支持的请求方法提供了别名。在使用别名方法时,url、method、data 不需要在 config 中指定。如果同时指定,config 中指定的字段会被覆盖掉。

  • un.request(config)
  • un.download(config)
  • un.upload(config)
  • un.get(url[, config])
  • un.delete(url[, config])
  • un.head(url[, config])
  • un.options(url[, config])
  • un.trace(url[, config])
  • un.connect(url[, config])
  • un.post(url[, data[, config]])
  • un.put(url[, data[, config]])
  • un.patch(url[, data[, config]])

实例

可以使用自定义配置创建一个实例。

un.create([config])

import { un } from "@uni-helper/uni-network";

const instance = un.create({
  baseUrl: "https://some-domain.com/api/",
  timeout: 1000,
  headers: { "X-Custom-Header": "foobar" },
});

instance.request({
  method: "POST",
  url: "/user/12345",
  data: {
    firstName: "Fred",
    lastName: "Flintstone",
  },
});

实例方法

以下是可用的实例方法。指定的配置将与实例的配置合并。

  • un.request(config)
  • un.download(config)
  • un.upload(config)
  • un.get(url[, config])
  • un.delete(url[, config])
  • un.head(url[, config])
  • un.options(url[, config])
  • un.trace(url[, config])
  • un.connect(url[, config])
  • un.post(url[, data[, config]])
  • un.put(url[, data[, config]])
  • un.patch(url[, data[, config]])
  • un.getUri([config])

请求配置

以下是创建请求时可以用的配置选项。只有 url 是必需的。如果没有指定 method 且没有指定 adapter,请求将默认使用 GET 方法。

{
  // `url` 是用于请求的服务器 URL
  url: '/user',

  // `baseUrl` 将自动加在 `url` 前面,除非 `url` 是一个绝对 URL 且选项 `allowAbsoluteUrls` 为 true
  // 设置一个 `baseUrl` 便于为实例方法传递相对 URL
  baseUrl: 'https://some-domain.com/api/',

  // 决定是否允许绝对 URL 覆盖配置的 `baseUrl`
  // 当设置为 true(默认)时,绝对值的 `url` 会覆盖 `baseUrl`
  // 当设置为 false 时,绝对值的 `url` 会始终被 `baseUrl` 前置
  allowAbsoluteUrls?: boolean,

  // 自定义请求头
  // 不能设置 Referer
  headers: {
    'content-type': 'application/json',
  },

  // `params` 是与请求一起发送的 URL 参数
  // 必须是一个普通对象或一个 URLSearchParams 对象
  // 要使用 URLSearchParams 对象,请使用 core-js 提供的 polyfill
  // 可参考构建与环境支持部分的说明或该仓库提供的 playground
  params: {
    ID: 12345
  },

  // `paramsSerializer` 是可选方法,主要用于序列化 `params`
  // 默认使用 [fast-querystring](https://github.com/anonrig/fast-querystring) 序列化,需要自行处理嵌套值
  // [picoquery](https://github.com/43081j/picoquery) 在 fast-querystring 基础上支持嵌套值、增加可配置性
  // [qs](https://github.com/ljharb/qs) 包含大量无用的兼容代码,占用额外体积,如无必要不建议使用
  // [qs](https://github.com/ljharb/qs) v6.10.0 引入了 `get-intrinsic` 导致结合微信小程序和微信小程序插件使用时出现报错,可使用 v6.9.7
  // [query-string](https://github.com/sindresorhus/query-string) 体积性能都较好,支持完善
  // [query-string](https://github.com/sindresorhus/query-string) 基于 [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component),它使用了部分小程序(如支付宝小程序)不支持的语法(可选的 catch 参数,Optional catch Binding),需自行修改处理
  paramsSerializer: (params) => { /* 返回一个字符串 */ }

  // `timeout` 指定请求超时的毫秒数
  // 如果请求时间超过 `timeout` 的值,则请求会被中断
  // 要设置永不超时,可以将其设置为 Number.POSITIVE_INFINITY
  // 默认值是实际调用的 API 的默认值,见 https://uniapp.dcloud.net.cn/collocation/manifest.html#networktimeout
  timeout: 1000,

  // `adapter` 允许自定义处理请求
  // 可以指定为 'request'、'upload' 和 'download' 三者之一
  // 也可以指定为一个方法,返回一个 Promise 并提供一个有效的响应
  // 如果你正在使用 un.request、un.download、un.upload、un.get 等别名方法,则无需再指定该键的值
  // 默认值是 'request'
  adapter: (config) => { /* ... */ },

  // `validateStatus` 定义了对于给定的 HTTP 状态码该 resolve 还是 reject
  // 如果 `validateStatus` 返回 `true`、`null` 或 `undefined`
  // 则 promise 将会被 resolve,否则会被 reject
  validateStatus: function (status) {
    return status >= 200 && status < 300; // 默认值
  },

  // 用于取消请求
  // 可参考取消请求部分的说明
  signal: new AbortController().signal,

  // 用于取消请求
  // 可参考取消请求部分的说明
  cancelToken: new CancelToken(function (cancel) { /* ... */ }),

  // 监听 HTTP Response Header 事件
  // 会比请求完成事件更早
  onHeadersReceived: (result) => { /* ... */ },

  // request 使用
  // 创建请求时使用的方法
  // 默认值是 'GET'
  method: 'GET',

  // request 使用
  // `data` 是作为请求体被发送的数据
  // 必须是以下类型之一:string、object、ArrayBuffer、ArrayBufferView、URLSearchParams
  data: {
    firstName: 'Fred'
  },
  // 这也是可行的
  // data: 'Country=Brasil&City=Belo Horizonte',

  // request 使用
  // 返回的数据类型
  // 如果设置为 json,会尝试对返回的数据做一次 JSON.parse
  // 默认值是 'json'
  dataType: 'json',

  // request 使用
  // 响应的数据类型,选项包括 'text' 和 'arraybuffer'
  // 默认值是 'text'
  responseType: 'text',

  // request 使用
  // 是否验证 ssl 证书
  // 默认值是 true
  sslVerify: true,

  // request 使用
  // 跨域请求时是否需要使用凭证
  // 默认值是 false
  withCredentials: false,

  // request 使用
  // 是否在 DNS 解析时优先使用 ipv4
  // 默认值是 false
  firstIpv4: false,

  // request 使用
  // 是否开启 http2
  // 默认值是 false
  enableHttp2: false,

  // request 使用
  // 是否开启 quic
  // 默认值是 false
  enableQuic: false,

  // request 使用
  // 是否开启缓存
  // 默认值是 false
  enableCache: false,

  // request 使用
  // 是否开启 HttpDNS 服务
  // 默认值是 false
  enableHttpDNS: false,

  // request 使用
  // HttpDNS 服务商 Id
  httpDNSServiceId: '',

  // request 使用
  // 是否开启 transfer-encoding chunked
  // 默认值是 false
  enableChunked: false,

  // request 使用
  // 是否在 wifi 下使用移动网络发送请求
  // 默认值是 false
  forceCellularNetwork: false,

  // request 使用
  // 监听 Transfer-Encoding Chunk Received 事件
  // 当接收到新的 chunk 时触发
  onChunkReceived?: (response) => { /* ... */ },

  // Request 使用
  // 是否可在 headers 中编辑 cookie
  // 默认为 false
  enableCookie?: boolean;

  // Request 使用
  // 是否开启云加速
  // 默认为 false
  cloudCache?: boolean | {
    // 用于指定 query 中哪些字段不作为缓存依据
    excludeURLQueries?: string[];
    // 用于表达云加速缓存的最快刷新时间
    // 单位 s
    minRefresh?: number;
    [key: string]: any;
  };

  // Request 使用
  // 控制当前请求是否延时至首屏内容渲染后发送
  // 默认为 false
  defer?: boolean;

  // upload 使用
  // 需要上传的文件列表,files 和 filePath 必填一个
  // 使用该参数时,filePath 和 name 无效
  // 不支持小程序
  files: [],

  // upload 使用
  // 文件类型
  fileType: 'image', // image, video, audio

  // upload 使用
  // 文件对象
  file: new File(),

  // upload 使用
  // 文件路径,files 和 filePath 必填一个
  //
  // download 使用
  // 文件下载后存储的本地路径
  filePath: '/fake/path',

  // upload 使用
  // 文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容
  name: 'file',

  // upload 使用
  // 一个对象,会作为 HTTP 请求中其它额外的 form data
  formData?: Record<string, any>,

  // download 使用
  // 下载进度变化时触发
  // 优先级 onDownloadProgress > onDownloadProgressUpdate > onProgress > onProgressUpdate
  onDownloadProgress?: UnOnProgress;

  // download 使用
  // 下载进度变化时触发
  // 优先级 onDownloadProgress > onDownloadProgressUpdate > onProgress > onProgressUpdate
  onDownloadProgressUpdate?: UnOnProgress;

  // upload 使用
  // 上传进度变化时触发
  // 优先级 onUploadProgress > onUploadProgressUpdate > onProgress > onProgressUpdate
  onUploadProgress?: UnOnProgress;

  // upload 使用
  // 上传进度变化时触发
  // 优先级 onUploadProgress > onUploadProgressUpdate > onProgress > onProgressUpdate
  onUploadProgressUpdate?: UnOnProgress;

  // upload / download 使用
  // 上传/下载进度变化时触发
  // 优先级 onUploadProgress / onDownloadProgress > onUploadProgressUpdate / onDownloadProgressUpdate > onProgress > onProgressUpdate
  onProgress?: UnOnProgress;

  // upload / download 使用
  // 上传/下载进度变化时触发
  // 优先级 onUploadProgress / onDownloadProgress > onUploadProgressUpdate / onDownloadProgressUpdate > onProgress > onProgressUpdate
  onProgressUpdate?: UnOnProgress;
}

响应结构

一个请求的响应包含以下信息。

{
  // `errMsg` 是可选的错误信息
  errMsg: '',

  // `errno` 是可选的错误代码
  errno: 0,

  // `profile` 是可选的调试信息
  profile: {},

  // `config` 是 `un` 请求的配置信息
  config: {},

  // `task` 是对应的 task 信息
  task: {}

  // `status` 来自服务器响应的 HTTP 状态码
  status: 200,

  // `statusText` 来自服务器响应的 HTTP 状态信息
  statusText: 'OK',

  // `headers` 是服务器响应头
  // 所有的 header 名称都是小写,而且可以使用方括号语法访问
  // 例如: `response.headers['content-type']`
  headers: {},

  // `data` 是由服务器提供的响应数据
  data: {},

  // request 特有
  // 服务器提供的 cookies 数据
  cookies: [],

  // download 特有
  // 临时本地文件路径
  // 没传入 filePath 指定文件存储路径时会返回,下载后的文件会存储到一个临时文件
  tempFilePath: '',

  // download 特有
  // 用户本地文件路径
  // 传入 filePath 时会返回,跟传入的 filePath 一致
  filePath: '',
}

当使用 then 时,你将接收如下响应:

un.get("/user/12345").then((response) => {
  console.log("errMsg", response?.errMsg);
  console.log("errno", response?.errno);
  console.log("profile", response?.profile);
  console.log("config", response?.config);
  console.log("status", response?.status);
  console.log("statusText", response?.statusText);
  console.log("headers", response?.headers);
  console.log("data", response?.data);
  console.log("cookies", response?.cookies);
  console.log("tempFilePath", response?.tempFilePath);
  console.log("filePath", response?.filePath);
});

当使用 catch,或者传递一个 rejection callback 作为 then 的第二个参数时,响应可以作为 error 对象被使用,正如在 错误处理 部分解释的那样。

默认配置

你可以指定默认配置,它将作用于每个请求。

全局配置默认值

import { un } from "@uni-helper/uni-network";

un.defaults.baseUrl = "https://api.example.com";

自定义实例默认值

import { un } from "@uni-helper/uni-network";

// 创建实例时配置默认值
const instance = un.create({
  baseUrl: "https://api.example.com",
});

// 创建实例后修改默认值
instance.defaults.baseUrl = "https://api.another-example.com";

配置的优先级

配置将会按优先级进行合并。优先级从低到高是内置的默认值、实例的 defaults 配置、请求的 config。下面是一个例子。

// 使用库提供的默认配置创建实例
// 此时超时配置的默认值是实际调用的 API 的默认值
const instance = un.create();

// 重写库的超时默认值
// 现在,所有使用此实例的请求都将等待 2.5 秒,然后才会超时
instance.defaults.timeout = 2500;

// 重写此请求的超时时间,因为该请求需要很长时间
instance.get("/longRequest", {
  timeout: 5000,
});

进阶

拦截器

在请求或响应被 then 或 catch 处理前拦截它们。

添加拦截器

可以全局添加请求或响应的拦截器。

import { un } from "@uni-helper/uni-network";

// 添加请求拦截器
un.interceptors.request.use(
  function (config) {
    // 在发送请求之前做些什么
    return config;
  },
  function (error) {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 添加响应拦截器
un.interceptors.response.use(
  function (response) {
    // 2xx 范围内的状态码都会触发该函数
    // 对响应数据做点什么
    return response;
  },
  function (error) {
    // 超出 2xx 范围的状态码都会触发该函数
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);

也可以给自定义实例添加请求或响应的拦截器。

import { un } from "@uni-helper/uni-network";

// 创建实例
const instance = un.create();

// 添加请求拦截器
instance.interceptors.request.use(() => {
  /* ... */
});

// 添加响应拦截器
instance.interceptors.response.use(() => {
  /* ... */
});

移除拦截器

可以移除单个请求或响应的拦截器。

import { un } from "@uni-helper/uni-network";

// 添加请求拦截器
const requestInterceptor = un.interceptors.request.use(() => {
  /* ... */
});
// 移除请求拦截器
un.interceptors.request.eject(requestInterceptor);

// 添加响应拦截器
const responseInterceptor = un.interceptors.response.use(() => {
  /* ... */
});
// 移除响应拦截器
un.interceptors.response.eject(responseInterceptor);

也可以移除所有请求或响应的拦截器。

import { un } from "@uni-helper/uni-network";

// 创建实例
const instance = un.create();

// 添加请求拦截器
instance.interceptors.request.use(() => {
  /* ... */
});
// 移除所有请求拦截器
instance.interceptors.request.clear();

// 添加响应拦截器
instance.interceptors.response.use(() => {
  /* ... */
});
// 移除所有响应拦截器
instance.interceptors.response.clear();

拦截器选项

当你添加请求拦截器时,@uni-helper/uni-network 默认认为它们是异步的。当主线程被阻塞时,这可能会导致 @uni-helper/uni-network 请求的执行延迟(底层为拦截器创建了一个 Promise,你的请求被放在了调用栈的底部)。

如果你的请求拦截器是同步的,你可以在选项对象中添加一个标志,告诉 @uni-helper/uni-network 同步运行代码,避免请求执行中的任何延迟。

import { un } from "@uni-helper/uni-network";

un.interceptors.request.use(
  (config) => {
    config.headers.test = "I am only a header!";
    return config;
  },
  null,
  { synchronous: true }
);

如果你想根据运行时检查来执行某个拦截器,你可以在 options 对象中设置 runWhen 函数。当且仅当 runWhen 的返回值为 false 时,拦截器不会被执行。该函数将和 config 对象一起被调用(别忘了,你也可以绑定你自己的参数)。当你有一个只需要在特定时间运行的异步请求拦截器时,这可能会很方便。

import { un } from "@uni-helper/uni-network";

const onGetCall = (config) => config.method.toUpperCase() === "GET";
un.interceptors.request.use(
  (config) => {
    config.headers.test = "special get headers";
    return config;
  },
  null,
  { runWhen: onGetCall }
);

多个拦截器

假设你添加了多个响应拦截器,并且响应是 fulfilled 状态时:

  • 按照添加的顺序执行每个拦截器
  • 只返回最后一个拦截器的结果
  • 每个拦截器都会收到其前一个拦截器的结果
  • 当 fulfilled 拦截器抛出时
    • 后面的 fulfilled 拦截器不会被调用
    • 后面的 rejection 拦截器会被调用
    • 一旦被捕获,后面的另一个 fulfilled 拦截器会被再次调用(就像在一个 Promise 链中一样)

错误处理

默认把每一个返回的状态代码不在 2xx 范围内的响应视为错误。

import { un } from "@uni-helper/uni-network";

un.get("/user/12345").catch((error) => {
  if (error.response) {
    // 请求成功发出且服务器也响应了状态码,但状态代码超出了 2xx 的范围
    console.log(error.response.data);
    console.log(error.response.status);
    console.log(error.response.headers);
  } else if (error.task) {
    // 请求已经成功发起,但没有收到响应
    // `error.task` 是 task 实例
    console.log(error.task);
  } else {
    // 发送请求时出了点问题
    console.log("Error", error.message);
  }
  console.log(error.config);
});

使用 validateStatus 配置选项,可以自定义抛出错误的 HTTP code。

import { un } from "@uni-helper/uni-network";

un.get("/user/12345", {
  validateStatus: (status) => {
    return status < 500; // 处理状态码小于 500 的情况
  },
});

如果你追求语义化,可以使用导出的和挂载的状态码、statuses-es、http-status-codes 或 node-http-status。

import { un, HttpStatusCode } from "@uni-helper/uni-network";

un.get("/user/12345", {
  validateStatus: (status) => {
    return status < HttpStatusCode.InternalServerError; // 处理状态码小于 500 的情况
    // return status < un.HttpStatusCode.InternalServerError; // 也可以使用挂载在 un 上的状态码
  },
});

使用 toJSON 可以获取更多关于 HTTP 错误的信息。

un.get("/user/12345").catch((error) => {
  console.log(error.toJSON());
});

如果需要针对 UnError 和非 UnError 做处理,可以使用导出的 isUnError 方法判断。

import { un, isUnError } from "@uni-helper/uni-network";

un.get("/user/12345").catch((error) => {
  if (isUnError(error)) {
    /* ... */
  } else {
    /* ... */
  }
});

取消请求

AbortController

支持使用 AbortController 取消请求。要使用 AbortController,请使用 abort-controller polyfill。

  • npm

    npm install abort-controller@^3.0.0
  • yarn

    yarn add abort-controller@^3.0.0
  • pnpm

    pnpm add abort-controller@^3.0.0
import { un } from "@uni-helper/uni-network";
import AbortController from "abort-controller/dist/abort-controller";
// ❌ 错误做法 1
// import AbortController from 'abort-controller';
// ❌ 错误做法 2
// import 'abort-controller/polyfill';

const controller = new AbortController();

un.get("/foo/bar", {
  signal: controller.signal,
}).then(function (response) {
  //...
});
// 取消请求
controller.abort();

CancelToken

你也可以使用 CancelToken 来取消请求。

import { un } from "@uni-helper/uni-network";

const CancelToken = un.CancelToken;
const source = CancelToken.source();

un.get("/user/12345", {
  cancelToken: source.token,
}).catch(function (thrown) {
  if (un.isCancel(thrown)) {
    console.log("Request canceled", thrown.message);
  } else {
    // 处理错误
  }
});

un.post(
  "/user/12345",
  {
    name: "new name",
  },
  {
    cancelToken: source.token,
  }
);
// 取消请求(信息是可选的)
source.cancel("Operation canceled by the user.");

你也可以通过向 CancelToken 构造函数传递一个执行函数来创建一个 CancelToken 实例。

import { un } from "@uni-helper/uni-network";

const CancelToken = un.CancelToken;
let cancel;

un.get("/user/12345", {
  cancelToken: new CancelToken(function executor(c) {
    cancel = c;
  }),
});

// 取消请求
cancel();

你可以用同一个 CancelToken / AbortController 取消几个请求。

如果在发起请求的时候已经取消请求,那么该请求就会被立即取消,不会真正发起请求。

TypeScript 支持

@uni-helper/uni-network 使用 TypeScript 编写,你可以享受到完整的 TypeScript 支持。

最常见的一个类型问题是,调用 API 时得不到响应数据和发送数据的类型。

import { un } from "@uni-helper/uni-network";

// response 的类型是 UnResponse<UnData, UnData>
// response.data 的类型是 UnData,你希望是 Record<string, any>
const response = await un({
  method: "post",
  url: "/user/12345",
  // 以下 data 的类型是 UnData,你希望是 Record<string, string>
  data: {
    firstName: "Fred",
    lastName: "Flintstone",
  },
});

这可以通过设置两个范型类型来解决,两个范型类型依次分别对应响应数据和发送数据的类型。

import { un } from "@uni-helper/uni-network";

// response 的类型是 UnResponse<Record<string, any>, Record<string, string>>
// response.data 的类型是 Record<string, any>
const response = await un<
  Record<string, any>, // 对应 response.data 类型
  Record<string, string> // 对应传参中 data 类型
>({
  method: "post",
  url: "/user/12345",
  // 以下 data 的类型是 Record<string, string>
  data: {
    firstName: "Fred",
    lastName: "Flintstone",
  },
});

而另一个常见的类型问题是,使用响应拦截器后响应类型不正确。

import { un } from "@uni-helper/uni-network";

// 添加响应拦截器直接返回 response.data
un.interceptors.response.use((response) => response.data);

// response 的类型是 UnResponse<UnData, UnData>,你希望是 Record<string, any>
// response.data 的类型是 UnData,你希望是 Record<string, any>
const response = await un({
  method: "post",
  url: "/user/12345",
  // 以下 data 的类型是 UnData,你希望是 Record<string, string>
  data: {
    firstName: "Fred",
    lastName: "Flintstone",
  },
});

这需要设置三个范型类型来解决,三个范型类型依次分别对应响应数据、发送数据、响应的类型。

import { un } from "@uni-helper/uni-network";

// 添加响应拦截器直接返回 response.data
un.interceptors.response.use((response) => response.data);

// response 的类型是 Record<string, any>
// response.data 的类型是 Record<string, any>
const response = await un<
  Record<string, any>, // 对应 response.data 类型
  Record<string, string>, // 对应传参中 data 类型
  Record<string, any> // 对应 response 类型
>({
  method: "post",
  url: "/user/12345",
  // 以下 data 的类型是 Record<string, string>
  data: {
    firstName: "Fred",
    lastName: "Flintstone",
  },
});

如果你只想修改响应的类型,而不修改其它类型,你仍然需要书写三个范型类型。这和 axios 的范型类型设计不同,因为 uni-app 对数据类型有更严格的要求。

你可以从 @uni-helper/uni-network 中导入 UnData 以保持前两个范型类型的默认值。

import { un, type UnData } from "@uni-helper/uni-network";

// 添加响应拦截器直接返回 response.data
un.interceptors.response.use((response) => response.data);

// response 的类型是 Record<string, any>
// response.data 的类型是 UnData
const response = await un<
  UnData, // 对应 response.data 类型
  UnData, // 对应传参中 data 类型
  Record<string, any> // 对应 response 类型
>({
  method: "post",
  url: "/user/12345",
  // 以下 data 的类型是 UnData
  data: {
    firstName: "Fred",
    lastName: "Flintstone",
  },
});

高级功能

该部分目前较为简陋。欢迎 PR 贡献!🫡

对于缓存、去重、重试的高级功能,建议结合 @tanstack/query、swrv、vue-request、alova 等库使用。

如果你不希望引入过多的库导致占用体积过多,你也可以参考以下内容以实现部分高级功能。

缓存

请参考 Axios 如何缓存请求数据。

去重

请参考 Axios 如何取消重复请求 和 Axios 如何取消重复请求?取消重复请求方法有哪几种?。

重试

请参考 Axios 如何实现请求重试?。

响应失败不抛出错误

在某些情况下,你可能不希望响应失败抛出错误,这时候可以使用响应拦截器来处理。

import { un } from "@uni-helper/uni-network";

// 添加响应拦截器
un.interceptors.response.use(
  (response) => response,
  // 直接返回错误,不再需要使用 catch 来捕获
  // 需要注意返回值可能是 UnError 类型
  (error) => error
);

无感刷新登录态

在某些情况下,你可能希望无感刷新登录态,避免当前登录态过期后用户手动登录。

如果你有一个可以使用过期登录态换取新鲜登录态的接口,请参考 uni-ajax - FAQ - 无感刷新 Token。该部分代码实现略经修改也适用于使用双登录态的认证系统。

如果你正在使用一个使用双登录态的认证系统,请参考 项目中前端如何实现无感刷新 token! 和 基于 Axios 封装一个完美的双 token 无感刷新。

全局请求加载

请参考 uni-ajax - FAQ - 配置全局请求加载。这类做法不适用于局部加载展示。

组合式函数

如果你还不了解组合式函数,请先阅读 组合式 API 常见问答 和 组合式函数。

我们使用 vue-demi 和 vue-use 来同时支持 vue2 和 vue3。请先阅读它们的使用说明。

  • npm

    npm install @vueuse/core@^9.13.0
  • yarn

    yarn add @vueuse/core@^9.13.0
  • pnpm

    pnpm add @vueuse/core@^9.13.0

如果你希望使用 @vueuse/core>=10,请查看 dcloudio/uni-app#4604 内提供的解决方案。

从 @uni-helper/uni-network/composables 中导入组合式函数后即可使用。

import { useUn } from "@uni-helper/uni-network/composables";

useUn 的用法和 useAxios 几乎完全一致。这里不再赘述。

其它

构建与环境支持

目前 @uni-helper/uni-network 会使用 tsdown 将语法 Syntax 转译到 ES2017(即 ES8)。uni API 需要在项目构建时由 uni-app 官方提供的插件处理,其它 API 需要根据实际情况手动注入 Polyfill。

如果你希望提供更好的兼容性,请参考 这里。

比较

最常见的比较就是 axios 和 @uni-helper/uni-network 的比较。

axios 非常棒,@uni-helper/uni-network 的灵感也源于 axios,但 axios 存在几个相对严重的问题。

  • axios 面向浏览器和 Node.js,即使使用了 adapter,某些底层功能也可能会在小程序内报错。
  • axios 体积较大,会占用宝贵的小程序空间。
  • 如果你想要获取良好的 TypeScript,你需要修改 axios 大部分类型定义。

如果你因为某些原因坚持使用 axios,你可以查看 @uni-helper/axios-adapter 获取 adapter 支持。

以下是 @uni-helper/uni-network 与其它一些库的比较。如果你发现这里信息已经过时,欢迎提交 ISSUE 或 PR。

| | axios | luch-request | uni-ajax | @uni-helper/uni-network | | ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | 基本信息 | npm npm | npm npm | npm npm | npm npm | | 开发语言 | JavaScript | JavaScript | JavaScript | TypeScript | | 类型支持 | index.d.ts(没有考虑 uni-app) | index.d.ts(泛型支持较差) | index.d.ts | 包含 | | 运行环境 | 浏览器和 Node.js | uni-app | uni-app | uni-app | | Promise | √ | √ | √ | √ | | uni_modules | × | √ | √ | × | | npm 包 | √ | √ | √ | √ | | 实例化 | √ | √ | √ | √ | | 请求说明 | √ | √ | √ | √ | | 请求头 headers | AxiosHeaders | 普通对象 | 普通对象 | 普通对象 | | 请求参数 params | AxiosURLSearchParams | 普通对象 | 普通对象 | 普通对象或 URLSearchParams 对象 | | 请求转换 transformRequest | √ | × | × | × | | 响应说明 | √ | × | √ | √ | | 响应转换 transformResponse | √ | × | × | × | | 任务说明 | ×(没有考虑 uni-app  任务) | × | √(只有 requestTask  说明) | √(只有简单说明) | | 适配器 | √(内置 xhr 和 http) | × | √ | √ | | uni.request | ×(自行开发,还需要覆写类型) | √ | √ | √ | | uni.downloadFile | ×(自行开发,还需要覆写类型) | √ | ×(自行开发,还需要覆写类型) | √ | | uni.uploadFile | ×(自行开发,还需要覆写类型) | √ | ×(自行开发,还需要覆写类型) | √ | | 请求拦截器 | √ | √ | √ | √ | | 响应拦截器 | √ | √ | √ | √ | | 配置说明 | √ | √ | √ | √ | | 取消请求说明 | √ | × | √ | √ | | 错误处理说明 | √ | × | √ | √ | | 测试 | 完善 | 部分 | 无 | 部分 | | 使用示例 | √ | √ | √ | √ |

资源

致谢

根据字母顺序排序。

参与贡献

欢迎提交 PR!请先阅读贡献指南。

许可证

MIT