更新记录

1.0.0(2026-09-27)

  • 提供 Android、iOS、鸿蒙统一的 HTTP 会话,createHttp 返回会话对象;
  • 支持断点续传(上传、下载)、固定服务端证书、禁用代理(防止抓包)、后台传输、缓存、拦截和取消;
  • 会话上可更换 token、清空缓存、关闭连接;上传和下载走同一条会话;
  • 支持VDOM、vapor编译模式的语法。

平台兼容性

uni-app(4.86)

Vue2 Vue3 Chrome Safari app-vue app-nvue Android iOS 鸿蒙
√ √ × × √ √ √ √ √
微信小程序 支付宝小程序 抖音小程序 百度小程序 快手小程序 京东小程序 鸿蒙元服务 QQ小程序 飞书小程序 小红书小程序 快应用-华为 快应用-联盟
× × × × × × × × × × × ×

uni-app x(4.86)

Chrome Safari Android iOS 鸿蒙 微信小程序
× × √ √ √ ×

umi-http

uni-app x 的 HTTP 插件。三端共用一套会话 API:基础请求、拦截器、缓存、DNS、证书、断点续传和大文件后台传输。

鸿蒙网络栈使用 Remote Communication Kit 的 rcp.Session,不走 @ohos.net.http。会话模型参照 OkHttp OkHttpClient、Alamofire Session 和 RCP createSession:一个客户端持有一条长连接会话,后续请求复用这条会话。

具体使用方法查看示例代码,有完整的写法示例。docs目录下也有完整的封装代码,可以参照。

风险检测、网络环境 配合上面的插件实现屏蔽抓包工具抓取接口数据。

特性

会话上的设置对这条会话之后的请求生效。单次请求可以再覆盖代理、缓存、超时和跟踪。

断点续传

上传和下载都可以从中断处继续。resume: true 时,下载读取目标文件已有字节,带 Range 接着写;上传从 resumeOffset 带 Content-Range 接着传,不传 resumeOffset 时从 0 开始。进度记在本地文件里。进程被回收后,再次调用并打开 resume,会从文件长度继续。服务端下载需要支持 Range,上传需要支持 Content-Range。同一次传输里,用返回的 TransferTask 调用 pause() 和 resume()。表单上传(传了 name)按整文件提交;要续传时打开 resume,按原始文件发送。

固定服务端证书

createHttp 的 ssl.policy 设为 custom,caPath 指向证书文件的绝对路径。这条会话只按该证书校验服务端。policy 为 system 时使用系统信任库,为 skip 时跳过校验。默认是 system。

ssl: {
    policy: 'custom',
    caPath: '/data/storage/el2/base/haps/entry/files/server.pem'
} as SslOptions

禁用代理

proxy 设为 no-proxy 时请求直连。设为 system 时使用系统代理。写在 createHttp 上时,这条会话之后的请求都按它执行。单次请求、上传和下载的 proxy 可以覆盖会话上的值。

自定义 DNS

dnsRules 把域名固定到指定 IP,可选端口。dnsServers 指定 DNS 服务器。dnsOverHttps 走 DoH。三者都写在会话配置上。

后台传输

上传和下载设 background: true 后,退到后台继续传。鸿蒙申请 DATA_TRANSFER 长时任务,Android 用前台服务,iOS 用 background URLSession。各端还要按「权限」补配置。

缓存、拦截和取消

GET 和 HEAD 按 cachePolicy 缓存在内存或磁盘,有效期由 cacheTtlMs 控制。clearCache() 清掉这条会话的内存和磁盘缓存。useRequest 在地址拼接前改请求;会话上的 token 自动写入鉴权头,登录后用 setToken 更换。普通请求把 createAbortController() 的 signal 传进去,再 abort() 取消。上传和下载用 TransferTask 的 pause()、resume()、cancel()。

范围请求和耗时

transferRange 按字节范围取响应,to 可省略。enableTrace: true 时,响应带各阶段耗时、远端 IP、端口和协议。三端默认协商 HTTP/2。Android 把 enableHttp2 设为 false 时固定 HTTP/1.1。

能力对照

RCP 能力 插件
PATCH、OPTIONS、HEAD patch / httpOptions / head,也可在 request 里写 method
Session 统一管理,自动复用连接 createHttp() 创建一条会话。鸿蒙 rcp.createSession,Android OkHttpClient 连接池,iOS 同一条 URLSession
请求拦截,统一处理 Token 会话上的 token 自动写入鉴权头;useRequest 在拼接地址前改请求;setToken 更换 token
内置缓存 cachePolicy: none、memory、disk、memory-and-disk
自定义 DNS 服务器或静态规则 dnsServers、dnsRules、dnsOverHttps
忽略 SSL、自定义证书 ssl.policy: system、skip、custom,自定义证书用 caPath
禁用代理 proxy: system、no-proxy。会话上设置对后续请求生效,单次请求可再覆盖
API 24+ 并行建链 鸿蒙由 RCP Session 在 API 24+ 上并行完成 TCP/TLS,插件保持会话不重复握手
transferRange 请求上的 transferRange,下载/上传上的 resume
TLS + HTTP/2 三端默认协商 HTTP/2。Android 可用 enableHttp2: false 固定 HTTP/1.1
HttpEventsHandler / 进度 上传下载的 onProgress。鸿蒙走 httpEventsHandler 和下载流 writeSync
各阶段耗时、IP、端口 enableTrace: true 时响应带 trace
取消普通请求 createAbortController(),把 signal 传给请求,abort() 取消
暂停、继续、取消传输 TransferTask.pause() / resume() / cancel(),或 pauseTransfer / resumeTransfer / cancelTransfer

API

从 @/uni_modules/umi-http 导入。createHttp 返回会话对象,请求、上传、下载、拦截和关闭都在这个对象上。url 可以写相对路径,会拼上这条会话的 baseUrl。

不带会话的 request、get、post、put、patch、del、head、httpOptions、upload、download 共用一条默认会话。默认会话没有 baseUrl、token 和自定义 DNS,地址要写绝对 URL。

import { abort, createAbortController, createHttp, readJson } from '@/uni_modules/umi-http'

createHttp

创建一条会话,返回 UmiHttp。同一条会话上的请求复用连接。config 可以传 null,字段都可选。

字段 作用
baseUrl 地址前缀。相对路径会拼到它后面;已经是 http:// 或 https:// 的地址原样使用
headers 这条会话上每个请求都会带的头
token 自动写入鉴权头。请求自己已经带了同名头时不再覆盖
tokenHeader 鉴权头名称,默认 Authorization
tokenPrefix 写在 token 前面的文字,默认 Bearer(含末尾空格)。不需要前缀时传空字符串
timeout 单次请求超时,毫秒,默认 15000。设为 0 时这一次不按 15 秒截断:Android 不限制,iOS 和鸿蒙按 7 天
connectTimeout 建连超时,毫秒,默认 15000
cachePolicy none、memory、disk、memory-and-disk。默认 none。只缓存 GET 和 HEAD
cacheTtlMs 缓存有效期,毫秒,默认 300000
cacheDir 磁盘缓存目录。不传时鸿蒙缓存只留在当前进程内存
enableHttp2 是否协商 HTTP/2,默认协商。Android 设为 false 时固定 HTTP/1.1
enableTrace 为 true 时,响应带 trace(各阶段耗时、远端 IP、端口、协议)
proxy system 使用系统代理,no-proxy 直连。不传时走系统代理。单次请求可以再覆盖
ssl { policy, caPath }。policy 为 system(系统校验)、skip(跳过校验)、custom(用 caPath 指向的证书)
dnsRules 静态解析:{ host, ipAddresses, port },把域名固定到指定 IP,port 可省略
dnsServers DNS 服务器:{ ip, port },port 可省略
dnsOverHttps DoH 地址
const config : HttpSessionConfig = {
    baseUrl: 'https://api.example.com',
    token: 'token-value',
    tokenHeader: 'Authorization',
    tokenPrefix: 'Bearer ',
    timeout: 15000,
    connectTimeout: 10000,
    cachePolicy: 'memory-and-disk',
    cacheTtlMs: 300000,
    enableTrace: true,
    enableHttp2: true,
    ssl: {
        policy: 'system'
    } as SslOptions,
    proxy: 'no-proxy',
    dnsRules: [{
        host: 'api.example.com',
        ipAddresses: ['203.0.113.10'],
        port: 443
    }]
}
const http = createHttp(config)

默认会话上的请求

这些函数不接收会话 id。data 和 options 可以不传,也可以传 null。

API 作用
request(options) 按 options.method 发请求。不写 method 时是 GET。方法可以是 GET、POST、PUT、DELETE、HEAD、OPTIONS、PATCH、TRACE
get(url, data?, options?) GET。data 是 UTSJSONObject,会拼到 URL 后面。data 和 options 都可以不传
post(url, data?, options?) POST。data 是字符串或 UTSJSONObject。data 和 options 都可以不传
put(url, data?, options?) PUT。data 和 options 都可以不传
patch(url, data?, options?) PATCH。data 和 options 都可以不传
del(url, data?, options?) DELETE。data 是字符串或 UTSJSONObject,作为请求体。data 和 options 都可以不传
head(url, options?) HEAD。options 可以不传
httpOptions(url, options?) OPTIONS。函数名不用 options,避免和请求参数重名。options 可以不传

HttpRequestOptions 里和本次调用相关的字段:

字段 作用
url 地址。request 必填;快捷方法把第一个参数写入这里
method 覆盖方法,只在 request 里需要
headers 本次请求附加的头
query 查询参数,拼到 URL 后面。get 的第二个参数会写入这里;两边都有时以第二个参数为准
data 请求体。对象按 JSON 发送;字符串按原文发送
contentType 请求体类型。不传时,对象默认 application/json
timeout / connectTimeout 覆盖会话上的超时
transferRange { from, to },按字节范围取响应。to 可省略
enableTrace 覆盖会话上的跟踪开关
throwOnError 默认 true:HTTP 状态不在 2xx 时以 9010006 拒绝。设为 false 时照常返回响应
cachePolicy 覆盖会话上的缓存策略
proxy 覆盖会话上的代理
signal createAbortController() 返回的 signal,用来取消这一次请求

成功时得到 HttpResponse:statusCode、headers、data(字符串)、fromCache、trace。trace 在打开跟踪且不是缓存命中时才有值,字段为 dnsMs、connectMs、tlsMs、requestMs、responseMs、totalMs、remoteIp、remotePort、protocol、reusedConnection。

const query = new UTSJSONObject()
query['page'] = '1'
const body = new UTSJSONObject()
body['name'] = 'Ada'

const list = await get('https://api.example.com/users', query, {
    url: 'https://api.example.com/users',
    timeout: 8000
} as HttpRequestOptions)

const created = await post('https://api.example.com/users', body, null)

const traced = await request({
    url: 'https://api.example.com/health',
    method: 'GET',
    enableTrace: true,
    throwOnError: false
} as HttpRequestOptions)

会话上的请求

方法都在 createHttp() 返回的对象上。url 可以是相对路径。带请求体的方法里,data 是字符串或 UTSJSONObject。data 和 options 可以不传,也可以传 null。

方法 作用
request(options) 按 options.method 发请求。不写 method 时是 GET。适合 OPTIONS、TRACE,或一次写完头、查询和请求体
get(url, data?, options?) GET。data 拼到 URL 后面。data 和 options 都可以不传
post(url, data?, options?) POST。对象按 JSON 发送,字符串按原文发送。data 和 options 都可以不传
put(url, data?, options?) PUT,整资源替换。data 和 options 都可以不传
patch(url, data?, options?) PATCH,部分更新。data 和 options 都可以不传
del(url, data?, options?) DELETE。data 是字符串或 UTSJSONObject,作为请求体。data 和 options 都可以不传
head(url, options?) HEAD,只要响应头。options 可以不传
httpOptions(url, options?) OPTIONS。options 可以不传
upload(options) 上传,返回 TransferTask。走这条会话的前缀、鉴权、DNS、证书和代理
download(options) 下载,返回 TransferTask
useRequest(interceptor) 注册请求拦截器。拦截器先改 url、query、headers、data,然后会话再拼接地址并写入 token。在已有 headers 上赋值,整份替换会清掉这次请求自己带的头
useResponse(interceptor) 注册响应拦截器。直接改入参 HttpResponse 上的字段,按注册顺序执行
useError(interceptor) 注册错误拦截器。入参是 HttpError,用来记日志。取消(9010005)不会进来。请求仍然按原错误拒绝
setToken(token) 更换这条会话之后请求使用的 token。传空字符串则不再写鉴权头。已有同名头时不覆盖
clearCache() 清掉这条会话的内存缓存和磁盘缓存
close() 关闭会话并释放连接。之后再请求会以 9010008 拒绝

readJson(response) 把 HttpResponse.data 解析成 UTSJSONObject。正文不是 JSON 对象时返回 null。

const markRequest : RequestInterceptor = (options : HttpRequestOptions) : void => {
    const headers = new UTSJSONObject()
    const current = options.headers
    if (current != null) {
        const keys = UTSJSONObject.keys(current)
        for (let i = 0; i < keys.length; i++) {
            const key = keys[i]
            const value = current.getString(key)
            if (value != null) {
                headers[key] = value
            }
        }
    }
    headers['X-Umi'] = '1'
    options.headers = headers
}
http.useRequest(markRequest)

const page = new UTSJSONObject()
page['page'] = '1'
const response = await http.get('/users', page)
const users = readJson(response)

const body = new UTSJSONObject()
body['name'] = 'Ada'
const created = await http.post('/users', body, null)

const replaced = await http.put('/users/1', body, null)

const patchBody = new UTSJSONObject()
patchBody['name'] = 'Grace'
const patched = await http.patch('/users/1', patchBody, null)

const removed = await http.del('/users/1')

const headersOnly = await http.head('/users/1', null)

const traced = await http.request({
    url: '/health',
    method: 'GET',
    enableTrace: true,
    throwOnError: false
} as HttpRequestOptions)

http.setToken('next-token')
http.clearCache()
http.close()

post 也可以直接传字符串,并用 contentType 说明请求体类型:

const raw = '{"name":"Ada"}'
const posted = await http.post('/users', raw, {
    url: '/users',
    contentType: 'application/json'
} as HttpRequestOptions)

取消普通请求

API 作用
createAbortController() 返回 { id, signal }。signal 传给一次或多次普通请求
abort(signalId) 取消这个 controller 上还没结束的请求。参数用 controller.id(与 signal.id 相同)

取消后 Promise 以 9010005 拒绝。同一个 signal 在 abort() 之后再使用,请求不会发出。内存缓存已经命中时没有网络请求可取消。

const controller = createAbortController()
const pending = http.get('/users', null, {
    url: '/users',
    signal: controller.signal
} as HttpRequestOptions)
abort(controller.id)

上传和下载

API 作用
upload(options) / download(options) 用默认会话传输,返回 TransferTask
http.upload(options) / http.download(options) 用 createHttp 返回的会话传输,返回 TransferTask。相对路径会拼上 baseUrl,并带上会话的鉴权头

UploadOptions / DownloadOptions:

字段 作用
url 地址。指定会话上的下载可以写相对路径
filePath 本地文件绝对路径。上传读这个文件,下载写到这个文件
name 只用于上传。传入后按 multipart 表单提交,这个值是文件字段名
fileName 表单里的文件名
mimeType 文件类型,默认 application/octet-stream
formData 表单里的其他字段
headers 本次传输附加的头
method 上传默认 POST,下载默认 GET
resume 为 true 时断点续传。下载从目标文件已有字节继续,并带 Range;上传从 resumeOffset 继续,并带 Content-Range
resumeOffset 上传续传的起始字节。不传时从 0 开始
background 为 true 时退到后台继续传输。各端还要按下面「权限」补配置
timeout / connectTimeout 覆盖会话超时。上传和下载不传 timeout 时按 0:Android 不限制,iOS 和鸿蒙按 7 天
proxy 覆盖会话代理
throwOnError 默认非 2xx 会失败。设为 false 时仍按成功回调返回
onProgress 进度回调,会多次触发。参数是 TransferProgress:taskId、bytesTransferred、totalBytes、progress(0–100)
success / fail / complete 结束回调。fail 收到 HttpError

TransferResult:taskId、filePath、statusCode、bytesTransferred、totalBytes。

upload / download 返回的 TransferTask:

方法 作用
finished() 返回 Promise<TransferResult>,传输结束时完成
pause() 暂停
resume() 继续
cancel() 取消。上传和下载的取消用这个方法,不用 abort()

任务 id 已经单独保存时,也可以不持有 TransferTask,直接按 id 控制:

API 作用
pauseTransfer(taskId) 暂停这次上传或下载
resumeTransfer(taskId) 从暂停处继续
cancelTransfer(taskId) 取消这次上传或下载

taskId 来自 TransferTask.taskId,或进度回调 TransferProgress.taskId。id 为空时这三个函数不做事。持有 TransferTask 时,直接调用它的 pause()、resume()、cancel()。

const task = download({
    url: 'https://example.com/a.zip',
    filePath: '/data/storage/el2/base/haps/entry/files/a.zip',
    resume: true,
    background: true,
    : (progress : TransferProgress) : void => {
        console.log(progress.progress)
    }
} as DownloadOptions)
const saved = await task.finished()

const uploaded = upload({
    url: 'https://example.com/files',
    filePath: '/data/storage/el2/base/haps/entry/files/a.zip',
    name: 'file',
    fileName: 'a.zip'
} as UploadOptions)
await uploaded.finished()

resume: true 时,下载从目标文件已有字节数继续。表单上传(传了 name)按整文件提交;要续传时不要同时依赖 multipart,打开 resume 即可走原始文件。

background: true 时:

  • 鸿蒙:RCP 继续传输,并申请 DATA_TRANSFER 长时任务。应用 Ability 里把上下文放到 globalThis.abilityContext,否则传输仍会执行,但系统不一定允许退到后台后继续。
  • Android:前台服务保活,OkHttp 按文件偏移续写。
  • iOS:URLSessionConfiguration.background,并用 beginBackgroundTask 覆盖切后台瞬间。

断点保存在目标文件本身。进程被回收后,再次调用并打开 resume 即可从文件长度继续。服务端需要支持 Range;上传续传需要支持 Content-Range。本地文件已经覆盖完整资源时,服务端会返回 416,下载按成功结束,不再把这段响应当成失败。

权限

普通请求只需要网络权限。只有调用上传或下载并传入 background: true 时,才需要各端的后台传输配置。不用后台传输的工程不必声明这些项。

Android

权限写在工程 manifest.json 的 app-android.distribute.permissions。插件 utssdk/app-android/AndroidManifest.xml 里仍保留下面全部权限,引入插件时会合并。前台服务组件不在插件清单里,只有使用后台传输的工程才要自己注册。

始终需要:

"permissions": [
  "<uses-permission android:name=\"android.permission.INTERNET\"/>", // 发起网络请求
  "<uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\"/>" // 读取网络连接状态
]

仅 background: true 时再加:

"permissions": [
  "<uses-permission android:name=\"android.permission.WAKE_LOCK\"/>", // 传输期间保持 CPU 唤醒,避免息屏中断
  "<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\"/>", // 启动前台服务,后台传输不被系统回收
  "<uses-permission android:name=\"android.permission.FOREGROUND_SERVICE_DATA_SYNC\"/>", // Android 14 及以上声明前台服务类型为数据同步
  "<uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\"/>" // 展示前台服务通知,Android 13 及以上需用户授权
]

同一情况下,还要在工程根目录注册前台服务。manifest.json 不能声明 <service>。参考本仓库 nativeResources/android/AndroidManifest.xml:

<application>
    <service
        android:name="com.umi.http.TransferService"
        android:exported="false"
        android:foregroundServiceType="dataSync" />
</application>

exported="false" 表示其他应用不能启动该服务。foregroundServiceType="dataSync" 表示前台服务类型是数据同步,需与 FOREGROUND_SERVICE_DATA_SYNC 一起声明。未注册这个服务时,background: true 在 Android 上会启动失败。

iOS

普通 HTTPS 请求没有额外隐私描述。仅 background: true 时,在工程 manifest.json 的 app-ios.distribute 增加后台能力,云端打包后生效。参考本仓库 manifest.json:

"UIBackgroundModes": "fetch" // 后台 URLSession 在应用退到后台后继续上传和下载

鸿蒙

网络权限写在 harmony-configs/entry/src/main/module.json5。参考本仓库同一文件。

始终需要:

{
  // 发起网络请求
  "name": "ohos.permission.INTERNET"
}

仅 background: true 时,再声明长时任务,并在入口 Ability 上打开 dataTransfer。说明文字放在 harmony-configs/entry/src/main/resources/base/element/string.json,以及 zh_CN、en_US 下同名文件的 background_transfer。参考本仓库 module.json5:

{
  "requestPermissions": [
    {
      // 退到后台后继续大文件传输
      "name": "ohos.permission.KEEP_BACKGROUND_RUNNING",
      "reason": "$string:background_transfer",
      "usedScene": {
        "abilities": ["EntryAbility"],
        "when": "inuse"
      }
    }
  ],
  "abilities": [
    {
      // 后台数据传输,对应长时任务 DATA_TRANSFER
      "backgroundModes": ["dataTransfer"]
    }
  ]
}

应用 Ability 里把上下文放到 globalThis.abilityContext,否则长时任务申请不到,传输仍会执行,但系统不一定允许退到后台后继续。

文件路径使用应用沙箱绝对路径。磁盘缓存目录通过 cacheDir 传入;不传时鸿蒙缓存只在当前进程内存中。

平台实现

  • 鸿蒙:@kit.RemoteCommunicationKit 的 rcp.createSession、fetch、transferRange、TracingConfiguration.httpEventsHandler、静态 DNS / DNS over HTTPS、remoteValidation。
  • Android:OkHttp 4.12。连接池、缓存、EventListener 耗时、自定义 Dns、证书。后台传输使用前台服务。
  • iOS:一条 URLSession 复用连接,URLSessionTaskMetrics 记录耗时和远端地址。后台传输使用 background session。

忽略证书校验只在 ssl.policy = "skip" 时生效,默认仍然走系统校验。

错误码

码 含义
9010001 参数或 URL 无效
9010002 网络请求失败
9010003 超时
9010004 证书校验失败
9010005 已取消
9010006 HTTP 状态不在 2xx。throwOnError: false 时改为正常返回
9010007 文件读写失败
9010008 会话不存在或已关闭

隐私、权限声明

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

需要网络权限。后台大文件传输在 Android 使用前台服务通知,在鸿蒙需要长时任务权限。

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

插件只按调用方传入的地址发起请求,不额外采集或上报数据

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

无

暂无用户评论。