更新记录
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 | 会话不存在或已关闭 |

收藏人数:
购买源码授权版(
试用
使用 HBuilderX 导入示例项目
赞赏(0)
下载 1473
赞赏 4
下载 12641643
赞赏 1950
赞赏
京公网安备:11010802035340号