更新记录

1.0.0(2026-07-26)

  • 首次发布,支持 uni-app / uni-app x 的 Android 与 iOS App。
  • 支持本地 HTTP 服务的创建、启动、停止、重启、销毁和状态查询。
  • 支持动态路由、路径参数、查询参数、JSON / 文本请求与响应、自定义状态码和响应头。
  • 支持静态目录挂载、目录索引、MIME 推断、可选目录列举和 Cache-Control
  • 支持文件响应、Range / HEAD、multipart 文件上传和 urlencoded 表单。
  • 支持 CORS、请求超时、连接数、请求体和上传大小限制。
  • 默认仅监听本机回环地址,可显式开放到局域网。
  • 提供生命周期事件、统一错误码和日志开关。

平台兼容性

uni-app(5.15)

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

uni-app x(5.15)

Chrome Safari Android iOS 鸿蒙 微信小程序
- - - -

本地 HTTP 服务(hans-http-server)

面向 uni-app x App 的本地 HTTP/1.1 UTS 插件:可挂载静态站点、注册动态接口、接收上传,并为本地媒体访问提供 MIME、RangeHEAD 基础能力。本文以 uni-app x 的 .uvue / UTS 用法为主。服务默认只监听本机回环,需要时再显式开放到局域网。

它能做什么

  • 在 App 内启动 / 停止一个 HTTP 服务,并获取可访问地址与端口。
  • 动态路由:GET / POST / PUT / PATCH / DELETE / OPTIONS / HEAD,支持 :param 路径参数。
  • 响应类型:JSON、文本、文件流(支持 Range / HEAD)、空响应;可自定义响应头与状态码。
  • 静态站点:挂载目录、目录索引、MIME 推断、可选目录列举、Cache-Control、路径越界拦截。
  • 媒体访问:Range206 Partial Content,支持区间与后缀区间)、HEAD 以及 mp4 / HLS 常用 MIME;实际播放效果取决于平台播放器支持。
  • 表单与上传:解析 application/x-www-form-urlencoded;将 multipart/form-data 文件写入受控目录并解析普通字段。
  • CORS:可配置来源白名单,自动处理预检与实际响应。
  • 生命周期事件、统一错误码、可开关的日志。

平台支持

uni-app x 平台 支持状态
Android App 支持
iOS App 支持
HarmonyOS App 不支持
Web / 小程序 不支持

兼容性说明:同一套公开 API 也可用于传统 uni-app Vue2 / Vue3 的 Android 与 iOS App;本文的代码示例统一采用 uni-app x 的 UTS 写法。nvue、Web、小程序和快应用不支持。

平台配置与权限

平台 配置要求
Android 插件自动声明 android.permission.INTERNET;最低 minSdkVersion 21
iOS 最低 deploymentTarget 12;使用 host: 'lan' 时,宿主 Info.plist 必须声明 NSLocalNetworkUsageDescription

host: 'lan' 会让同一局域网内的其他设备访问服务。仅在业务确实需要时启用,并由宿主应用负责访问控制和敏感文件隔离。

安装与导入

从 DCloud 插件市场将插件导入 uni-app x 项目。在 .uvue 页面的 <script setup lang="uts"> 中,从插件根目录导入函数和公开类型,不要直接引用 utssdk 内部文件:

import {
  createHttpServer,
  getResourcePath,
  HttpServer,
  HttpRequest,
  HttpServerInfo,
  HttpServerEvent,
} from '@/uni_modules/hans-http-server'

快速开始

以下代码放在 .uvue 页面的 <script setup lang="uts"> 中:

import {
  createHttpServer,
  getResourcePath,
  HttpServer,
  HttpRequest,
  HttpServerInfo,
  HttpServerEvent,
} from '@/uni_modules/hans-http-server'

const server: HttpServer = createHttpServer({
  host: 'loopback',          // 默认仅本机回环;'lan' 显式开放到局域网
  port: 0,                   // 0 = 由系统分配空闲端口
  logEnabled: true,
})

// 挂载静态目录(必须在 start 之前注册)
server.mount('/assets', {
  root: getResourcePath('/static'),
  index: 'index.html',
})

// 动态接口
server.route('GET', '/api/status', (req: HttpRequest, responseId: string): void => {
  server.respond(responseId, {
    statusCode: 200,
    bodyJson: { ok: true, time: Date.now() },
  })
})

server.route('GET', '/api/users/:id', (req: HttpRequest, responseId: string): void => {
  server.respond(responseId, {
    statusCode: 200,
    bodyJson: { id: req.params['id'], query: req.query },
  })
})

server.route('POST', '/api/upload', (req: HttpRequest, responseId: string): void => {
  // multipart 文件已落盘;form 为普通字段;files 为受控路径列表
  server.respond(responseId, {
    statusCode: 200,
    bodyJson: { files: req.files, fields: req.form },
  })
})

server.route('GET', '/api/file', (req: HttpRequest, responseId: string): void => {
  // 命中文件路由后,Range/HEAD 由插件自动处理
  server.respond(responseId, {
    statusCode: 200,
    filePath: getResourcePath('/files/media.bin'),
    contentType: 'application/octet-stream',
  })
})

server.on('started', (event: HttpServerEvent): void => {
  console.log('started', event.info)
})
server.on('error', (event: HttpServerEvent): void => {
  console.error('server error', event.message)
})

async function startServer(): Promise<void> {
  const info: HttpServerInfo = await server.start()
  console.log(info.urls)      // 例如 ['http://127.0.0.1:54321']
}

async function stopServer(): Promise<void> {
  await server.stop()         // 停止后可再次 start
}

async function destroyServer(): Promise<void> {
  await server.destroy()      // 永久释放,不可再 start
}

模块级 API

API 说明
createHttpServer(options?) 创建一个尚未监听端口的服务实例
getResourcePath(path) 将应用资源路径转换为当前平台原生文件系统可读取的路径
setLogEnabled(enabled) 设置插件级日志开关(影响当前模块的所有服务实例)
isLogEnabled() 获取当前插件日志开关

公开类型

所有公开类型都从插件根目录导入。interface.uts 是 API 类型契约,不要在业务代码中直接引用该文件。

类型 用途
HttpServer 服务实例及 mountroutestartstop 等方法
HttpServerHost / HttpServerOptions 监听模式与服务配置(包含 CORS 配置)
StaticMountOptions 静态目录挂载配置
HttpRequest / UploadedFile / HttpRouteHandler 动态路由收到的请求、上传文件与回调签名
HttpRouteResponse / HttpHeader 通过 respond() 提交的响应与响应头
HttpServerInfo / HttpServerStatus 启动结果与状态快照
HttpServerEvent / HttpServerEventListener 生命周期、错误事件与监听器签名
HttpServerFail / HttpServerErrorCode API 调用失败对象与稳定错误码
HttpHeaders / HttpJsonBody UTSJSONObject 别名,用于跨 UTS / 原生桥接的可序列化对象

路由回调会跨越 UTS 与原生层,参数和响应必须可序列化。JSON、query、params、headers 与 form 使用 UTSJSONObject;文件内容通过 filePath 返回,不直接在回调中传递二进制对象。

配置项(createHttpServer)

选项 默认 说明
host 'loopback' 'loopback' 仅本机回环;'lan' 开放到局域网
port 0 0 由系统分配空闲端口;否则监听指定端口
logEnabled false 是否输出生命周期与错误日志
maxConnections 16 最大并发连接数
requestTimeout 30000 单次请求处理超时(毫秒)
maxRequestBodySize 8 MiB 请求体上限(字节),超出返回 413
uploadDir 应用临时目录 multipart 文件落盘目录
maxUploadFileCount 20 单次上传文件数量上限
maxUploadFileSize 16 MiB 单个上传文件大小上限(字节)
cors null(关闭) CORS 配置,见下表

multipart 请求的总大小仍受 maxRequestBodySize 限制。需要接收大文件时,应同时调整请求体上限与单文件上限。

cors 配置:

字段 说明
allowedOrigins 必填;来源白名单,['*'] 表示允许任意;空数组等价于 ['*']
allowedMethods 允许的方法;省略时为 GET / POST / PUT / PATCH / DELETE / OPTIONS,如需 HEAD 应显式加入
allowedHeaders 允许的请求头,省略时回显客户端请求的头
allowCredentials 是否允许携带凭证(为 true 时不回写 *,回显具体 Origin
maxAgeSeconds 预检缓存时长

静态目录配置(StaticMountOptions)

mount() 只能在服务未运行时调用。同一路径下优先查找索引文件;找不到索引时,只有显式开启目录列举才会返回目录内容。

字段 默认 说明
root 必填;平台可读取的目录路径,应用资源建议通过 getResourcePath() 获取
index 'index.html' 目录索引文件;可使用逗号分隔多个候选,例如 'index.html,index.htm'
cacheControl 不发送 静态响应的 Cache-Control
allowDirectoryListing false 找不到索引文件时是否生成目录列表

服务实例方法

方法 说明
mount(path, options) 挂载静态目录(仅服务未运行时)
route(method, path, handler) 注册动态路由(仅服务未运行时)
respond(responseId, response) 完成动态请求;responseId 由路由回调提供
start() 启动监听,返回 Promise<HttpServerInfo>(含 urls
stop() 停止监听,可再次 start
destroy() 永久释放实例
status() 返回当前状态快照
on(event, listener) / off(event, id?) 订阅 / 取消订阅事件(starting/started/stopping/stopped/error

服务状态按 created -> starting -> running -> stopping -> stopped 变化,destroy() 后进入 destroyedstop() 后可以再次 start()destroy() 后不能再次启动。

请求 HttpRequest

字段 说明
id 请求标识
method / path 方法与路径
query 查询字符串键值(已按段解析)
params :param 路径参数
headers 请求头(键名小写)
remoteAddress 对端 IP
contentType / contentLength 内容类型与长度
bodyText 文本类请求体(非文本类为 null
bodyJson application/json 请求体(解析失败为 null
form multipart / urlencoded 普通字段
files 上传文件列表(fieldName/fileName/mimeType/size/path

响应 HttpRouteResponse(一次性)

原生路由回调的参数必须是可序列化数据,因此处理器收到 responseId,再通过 server.respond(responseId, response) 完成请求。每个请求只能响应一次;超过 requestTimeout 仍未响应时返回 504

字段 说明
statusCode HTTP 状态码(必填)
headers 可选响应头数组,元素为 { name, value }
bodyJson JSON 正文;自动使用 application/json; charset=utf-8
bodyText 文本正文;自动使用 text/plain; charset=utf-8
filePath 文件路径;自动支持 Range / HEAD
contentType 可选内容类型,会覆盖正文类型的默认值

bodyJsonbodyTextfilePath 最多设置一个;都不设置时发送空响应。

路由处理器可以在回调返回后再调用 respond(),但必须在 requestTimeout 内完成。超时会返回 504,之后再使用该 responseId 会按“响应已提交或不再等待”处理。

返回对象与事件

start() 返回 HttpServerInfo

字段 说明
id 服务实例 ID
host 实际绑定地址;loopback 通常为 127.0.0.1,LAN 通常为 0.0.0.0
port 实际监听端口;配置 port: 0 时由系统分配
urls 可直接访问的 URL 列表;LAN 模式会尽量包含实际 IPv4 地址
startedAt 启动成功时的毫秒时间戳

status() 返回 HttpServerStatus

字段 说明
id 服务实例 ID
state created / starting / running / stopping / stopped / destroyed
isRunning 当前是否已经开始监听
routeCount / mountCount 已注册的动态路由数和静态挂载数
info 运行时的 HttpServerInfo;未运行时为 null

生命周期监听器收到 HttpServerEvent

字段 说明
type 事件名:starting / started / stopping / stopped / error
serverId 服务实例 ID
timestamp 事件发生时的毫秒时间戳
message 生命周期或错误摘要
info 可用时携带 HttpServerInfo,否则为 null
data 可选扩展数据,当前无数据时为 null

默认值与安全

  • 默认仅 loopback:服务默认只监听本机回环地址;开放到局域网必须显式设置 host: 'lan'
  • 静态路径限定:静态服务将相对路径中的 .. 等片段清洗并二次校验,确保响应文件不会逃逸出挂载根目录,越界请求返回 403
  • 上传落盘受控:multipart 文件由插件写入受控 uploadDir(文件名随机化),客户端无法指定目标目录;超过数量 / 大小限制的请求会被拒绝。
  • 上传文件清理:上传文件不会由插件自动删除,业务处理完成后必须由宿主清理。Android 与 iOS 不承诺完全一致的失败残留清理行为,不要依赖失败请求自动清理目录。
  • 请求体限额:超过 maxRequestBodySize 的请求返回 413
  • CORS 默认关闭:未配置 cors 时不回写任何跨域头。
  • 日志安全:日志默认关闭;开启后仅记录生命周期与错误摘要,不写入 Cookie / Authorization / 请求体。

错误码

错误码跨平台稳定,errSubject 固定为 hans-http-server

import { HttpServerFail } from '@/uni_modules/hans-http-server'

try {
  const info = await server.start()
  console.log('listening', info.urls)
} catch (error) {
  const fail = error as HttpServerFail
  console.error(fail.errCode, fail.errMsg, fail.detail)
}

HttpServerFail 包含 errCodeerrSubjecterrMsg 和可空的 detail。HTTP 请求解析或尺寸超限会直接向客户端返回对应 HTTP 状态;下表主要用于调用插件 API 时捕获失败。

errCode 含义
9015801 配置非法
9015802 生命周期状态非法(如 destroy 后再调用、运行中重复 start
9015803 端口被占用
9015804 启动失败
9015805 路由 / 挂载注册非法
9015806 响应已提交(重复终止响应)
9015807 路由处理器失败
9015808 当前平台不支持该能力
9015809 静态路径不被允许
9015810 请求超过尺寸限制
9015899 未知错误

版本要求

范围 要求或验证基线
uni-app x HBuilderX 4.25+、uni-app x 3.1.0+
传统 uni-app 兼容 uni-app 3.1.0+,仅 Vue2 / Vue3 的 Android 与 iOS App
Android minSdkVersion 21
iOS deploymentTarget 12

功能限制

  • HTTPS / TLS
  • WebSocket / SSE / 流式响应
  • HTTP pipelining
  • HLS / mp4 的跨平台播放器兼容性保证
  • 请求体 chunked transfer encoding
  • App 进入后台后的持续运行(保活由宿主应用负责)
  • IPv6 监听

隐私、权限声明

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

网络访问与网络状态:用于在应用内提供本地 HTTP 服务,并在局域网模式展示设备可访问地址。

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

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

暂无用户评论。