asai-nodejs-host
v0.2.42
Published
asai for you
Readme
asai-nodejs-host — HTTP/WebSocket 服务器主机插件
功能概述
asai-nodejs-host 是系统的核心服务器引擎,基于 Node.js 原生 http/https 与 ws 库,负责:
- 多站点 HTTP/HTTPS 并行托管(
hosts) - 反向代理(
proxyhosts) - WebSocket 服务(鉴权、在线数限制、广播)
- 静态资源服务(SPA fallback、ETag、LRU 缓存)
- 日志、进程守护、传输层桥接(TCP/gRPC/RS485)
配置文件路径:webserver/websys/sys/asaihost.json(运行时挂载为 $asai.hostconfig)。
目录结构
asai-nodejs-host/
├── AsaiHost.ts ← npm/插件入口(fn + AsaiCommon + AsaiUtils + HostApi)
└── src/
├── index.ts ← 插件工厂:注册 workHandlers、StartAsaiHost
├── types.ts ← TypeScript 类型
├── host-api.ts ← 对外公开 API(禁止 deep import src/ 内部)
│
├── core/ ← 启动与配置
│ ├── init.ts ← initAsaiHost(IP/日志/进程/AES/注册表)
│ ├── host-config.ts ← getHostCFG / getProxyHostCFG / validateHostdir
│ ├── network.ts ← getIp / getHostIP
│ ├── time.ts ← getNowTime
│ └── index.ts
│
├── http/ ← HTTP 层
│ ├── server.ts ← 路由编排、启动、asai 守护
│ ├── security.ts ← 安全响应头、Userinfo 解析
│ ├── log.ts ← 请求日志过滤(skip / sample)
│ ├── static.ts ← 静态查找、ETag、SPA fallback
│ ├── connection.ts ← 连接数监控与限流
│ └── static-path-cache.ts
│
├── ws/ ← WebSocket 层
│ ├── server.ts ← WSS 创建与 connection 分发
│ ├── auth.ts ← 鉴权、登录态、踢下线
│ ├── message.ts ← 消息序列化、sendws/broadws
│ └── route-index.ts ← WS 路由前缀索引
│
├── proxy/
│ └── server.ts ← 反向代理
│
├── config/
│ ├── syscom.ts ← syscom 传输配置读取与归一化
│ └── validate.ts ← asaihost.json 启动校验
│
├── infra/ ← 基础设施
│ ├── logger.ts ← 缓冲日志、按日轮转
│ ├── process.ts ← 异常捕获、优雅关闭
│ ├── registry.ts ← API/WS 路由注册
│ ├── transport-bridge.ts
│ ├── safe-path.ts ← 路径白名单校验
│ └── secure-compare.ts
│
├── utils/
│ ├── userinfo.ts ← Userinfo AES 解密
│ ├── ws-mock.ts ← WS Mock 工具
│ └── index.ts
│
└── common/ ← 路由处理器基类(Api / Sys / Ws / WsClient)
└── server/源码仅保留 TypeScript(
tsx直接运行);syscom-config.ts为对外 API 兼容入口,指向config/syscom.ts。
asaihost.json 完整配置说明
配置加载后赋值给 $asai.hostconfig。各站点实际生效配置 = hosts.default 与 hosts.<站点名> 浅合并;代理同理 = proxyhosts.default + proxyhosts.<代理名>。
顶层字段
| 字段 | 类型 | 示例 | 说明 | 读取模块 |
|------|------|------|------|----------|
| website.title | string | "WEB" | 日志文件头 Software 名称 | infra/logger |
| website.ver | string | "1.0.0.0" | 日志文件头 Version | infra/logger |
| password | string | "asai" | 系统密码(必填,启动校验) | config/validate |
| ip | string | "asai" | 全局绑定 IP;"asai"=自动探测本机 IPv4 并 localhost 监听 | core/network |
| index | string | "index.html" | 默认首页文件名 | http/server |
| asaisn | string | — | Userinfo 解密盐(AsCode.asdecode) | utils/userinfo |
| wssec | string[] | ["asai","","-"] | WS 安全相关(业务层使用) | hostweb |
| pkg.type | number | 1 | 打包模式标识 | 业务层 |
tm — 定时器
| 字段 | 默认 | 说明 |
|------|------|------|
| tm.c | — | 通用定时(ms) |
| tm.d | 2000 | asai 守护重启延迟 / WS 踢下线探测超时 |
| tm.maxtry | 100 | 进程异常重启上限窗口内次数 |
| tm.restartwindow | 60000 | 异常重启统计窗口(ms) |
path — 路径
| 字段 | 说明 |
|------|------|
| path.mock | Mock 数据目录 |
| path.ip | IP 相关资源目录 |
zip
| 字段 | 说明 |
|------|------|
| zip.zipFileNameEncoding | 解压文件名编码,如 "gbk" |
logger — 日志
| 字段 | 类型 | 示例 | 说明 |
|------|------|------|------|
| logger.lv.view | number/bool | 2 | 控制台输出;truthy 时 WS message 也写日志 |
| logger.lv.record | number/bool | 1 | 是否写入日志文件 |
| logger.path.server | string | "./webdata/.../server/" | 服务端日志目录 |
| logger.path.client | string | — | 客户端日志目录 |
| logger.path.maxsize | number | 1048576 | 单文件上限(字节),超出自动轮转 |
| logger.sample | object | { "API": 0.15 } | 按日志类型采样率 0~1,降低高 QPS 写盘 |
| logger.skip | string[] | ["/sys/info/metrics"] | 静默路径;精确匹配或 * 前缀通配 |
guard — 进程守护(业务层 hostweb)
| 字段 | 说明 |
|------|------|
| guard.config | guard.json 路径 |
| guard.autoStartOnRestart | 重启后自动拉起子进程 |
| guard.default.* | 子进程默认参数(app/ispath/trymax/cfg 等) |
aes — 加密
| 字段 | 说明 |
|------|------|
| aes.lv | 加密等级;>1 时 API/WS 全量 AES |
| aes.keybase64 | AES 密钥(Base64) |
| aes.aad | 附加认证数据 |
| aes.keylength | 密钥长度(bit) |
| aes.ivlength | IV 长度 |
| aes.algorithm | 如 "aes-256-gcm" |
启动时若 aes.lv 有效且存在 AsAES,挂载 $asai.$lib.aesfns。
httpscert — 全局 HTTPS 证书
| 字段 | 说明 |
|------|------|
| httpscert.key | PEM 私钥(字符串或 Buffer) |
| httpscert.cert | PEM 证书 |
站点 httptype 为 https:// 时,优先用站点级 httpscert,否则回退全局。
mimetypes — 全局 MIME
扩展名 → Content-Type 映射。站点可覆盖:hosts.<name>.mimetypes 与全局合并。
hosts — HTTP/WS 站点
hosts.default(模板,不单独启动)
| 字段 | 类型 | 默认 | 说明 |
|------|------|------|------|
| close | 0/1 | 0 | 1 跳过启动 |
| port | number | 9198 | 监听端口 |
| httptype | string | "http://" | "http://" 或 "https://" |
| wstype | string | "ws://" | 控制台 WS 地址展示 |
| ip | string | — | 站点级绑定 IP,覆盖全局 |
| ws | 0/1 | — | 是否挂载 WebSocket |
| ckhttp | 0/1 | 0 | 启用 HTTP 连接数监控与限流 |
| ckws | 0/1 | 0 | 启用 WS 用户鉴权与在线表 |
| maxhttp | number | 100 | HTTP 最大并发连接 |
| maxws | number | 100 | WS 最大连接数(ckws 模式下按已登录用户计) |
| maxonline | number | 100 | 最大在线用户数(ckws) |
| oncors | 0/1 | 0 | API CORS 严格模式(0=*,1=校验 cors 列表) |
| cors | string[] | [] | 允许的 Origin 列表 |
| hostdirs | string[] | — | 静态文件查找目录(按序) |
| mimetypes | object | — | 站点级 MIME 覆盖 |
hosts.<站点名>.weburls — SPA 路由
| 字段 | 说明 |
|------|------|
| weburls.rewrite | true 启用 SPA fallback |
| weburls.webdir | 前端构建目录(如 "webclient") |
| weburls.keys | URL 前缀列表,匹配则返回 index.html |
静态查找顺序:hostdirs 各目录 → 未命中且启用 rewrite → fallback 到 webdir/index.html。
特殊站点名
| 名称 | 行为 |
|------|------|
| default | 仅作默认模板,不启动 |
| asai | 内置守护站点;端口冲突时进程退出或延迟重启 |
| 其它 | 须匹配 ^[a-zA-Z0-9_-]+$ 且长度 ≤100 |
示例(节选)
"estunweb": {
"ckhttp": 1,
"ckws": 1,
"ws": 1,
"maxhttp": 1000,
"maxws": 200,
"maxonline": 10,
"weburls": {
"rewrite": true,
"webdir": "webclient",
"keys": ["/cocontrol", "/couser"]
},
"hostdirs": ["home", "websys/webpage", "webdata/upload"]
}proxyhosts — 反向代理
proxyhosts.default
| 字段 | 默认 | 说明 |
|------|------|------|
| proxyhttptype | "http://" | 代理监听协议 |
| proxyport | — | 代理监听端口 |
| httptype | "http://" | 目标协议(用于自动拼 url) |
| port | — | 目标端口 |
| redirect | false | true 时 301 重定向而非转发 |
| maxSockets | 2000 | Agent 最大 socket |
| maxFreeSockets | 200 | 空闲 socket 池上限 |
| keepAlive | true | HTTP Agent keepAlive |
| timeout | 60000 | 请求超时(ms) |
| keepAliveMsecs | 30000 | keepAlive 间隔 |
| rejectUnauthorized | false | HTTPS 目标自签名证书 |
| passUserInfo | false | 是否向目标转发 Userinfo 头 |
proxyhosts.<代理名>
| 字段 | 说明 |
|------|------|
| url | 目标完整 URL;空则按 httptype+ip+port 自动拼接 |
| proxyip | 代理绑定 IP |
| proxyport | 代理端口 |
| proxyhttptype | 代理 HTTPS 时用 "https://" |
syscom — 传输层默认连接(TCP / gRPC / RS485)
推荐结构:syscom.{tcp|grpc|rs485}.default。启动时 normalizeHostConfig 会合并到顶层同名键,并兼容 legacy 键 1tcp/serial485 等。
通用 default 字段
| 字段 | 说明 |
|------|------|
| id | 连接 ID(如 testtcp) |
| label | 显示名称 |
| autoConnect | 启动时自动连接(默认 true,显式 false 关闭) |
| reconnect.enabled | 是否自动重连 |
| reconnect.maxRetries | 最大重试次数(默认 60 或 tm.maxtry) |
| reconnect.initialDelay | 首次重连延迟(ms) |
| reconnect.maxDelay | 最大重连间隔(ms) |
| reconnect.factor | 退避倍数 |
TCP default
| 字段 | 说明 |
|------|------|
| host | 目标主机 |
| port | 目标端口 |
gRPC default
同 TCP:host + port(如 50051)。
RS485 default
| 字段 | 说明 |
|------|------|
| path | 串口路径(Windows COM3,Linux /dev/ttyUSB0) |
| baudRate | 波特率 |
| dataBits / stopBits / parity | 串口参数 |
请求路由
| URL 前缀 | 处理器 | 注册来源 |
|----------|--------|----------|
| /sys/* | sysWork | hostweb 注入 |
| /api/* | apiWork | hostweb 注入 |
| /jsonp/* | jsonpWork | hostweb 注入 |
| 其它 | 静态文件 | http/static |
WebSocket 消息 → wsWork(hostweb 注入)。
模块职责速查
| 模块 | 核心导出 | 职责 |
|------|----------|------|
| core/init | initAsaiHost | 启动期挂载 $asai 方法、日志、进程、AES |
| core/host-config | getHostCFG | 合并并缓存 hosts/proxyhosts |
| http/server | startHTTPServer | HTTP 创建、路由、监听、asaiGuard |
| http/static | createStaticHandler | 静态文件 + SPA + ETag |
| http/connection | setupHttpConnectionMonitor | 80%/95% 阈值、空闲清理 |
| ws/server | createWSHost | WSS 生命周期 |
| ws/auth | isOkWs, loginWs | 用户名/Token/在线数鉴权 |
| proxy/server | startProxyServer | 反向代理、hop-by-hop 头过滤 |
| config/validate | validateHostConfig | 启动前 fail-fast 校验 |
| config/syscom | normalizeHostConfig | syscom 归一化 |
| infra/logger | initLog | $asai.$log、缓冲写盘 |
| infra/process | gracefulShutdown | SIGTERM/SIGINT 优雅关闭 |
| infra/registry | registerApi/Ws | 路由注册双写 $lib 与 hostserver* |
使用示例
import AsaiHost from './AsaiHost';
const { StartAsaiHost } = AsaiHost.fn($asai, {
sysWork: (req, res, hostdir) => { /* /sys */ },
apiWork: (req, res, hostdir) => { /* /api */ },
wsWork: (msg, ws, hostdir, req) => { /* WS */ },
jsonpWork: (req, res, hostdir) => { /* /jsonp */ },
});
StartAsaiHost();启动校验:
import { validateHostConfig, normalizeHostConfig } from './src/host-api';
const cfg = normalizeHostConfig(JSON.parse(fs.readFileSync('asaihost.json', 'utf8')));
const errors = validateHostConfig(cfg);
if (errors.length) throw new Error(errors.join('\n'));注意事项
- 处理器通过模块级
workHandlersMap 注册,不污染 global。 validateHostdir()拒绝default/asai作为普通站点名启动。- 静态路径经
resolvePathUnderRoots白名单校验,拒绝目录穿越;代理默认不透传 Userinfo。 - HTTP 连接监控间隔 5 分钟;超 95% 清理空闲 5 分钟以上连接。
- 日志异步缓冲写入,进程退出时
beforeExit刷盘。
配置 → 代码映射图
asaihost.json
├── website/password/ip/index/asaisn/aes/httpscert/mimetypes → 全局
├── logger.* → infra/logger, http/log
├── tm.* → core/init, ws/auth, infra/process
├── hosts.default + hosts.<site> → core/host-config → http/*, ws/*
│ ├── weburls.* → http/static (SPA)
│ ├── ckhttp/maxhttp → http/connection
│ └── ckws/maxws/maxonline → ws/auth
├── proxyhosts.default + proxyhosts.<name> → proxy/server
└── syscom.{tcp|grpc|rs485} → config/syscom → infra/transport-bridge版本与优化记录
- ✅ 模块级 workHandlers(替代 global)
- ✅ 静态 ETag / 304、LRU 路径缓存
- ✅ URL encodeURI 保护、日志 exit 刷盘
- ✅ WS send→close 竞争修复、代理 passUserInfo 开关
- ✅ HTTP 模块职责拆分(core/http/ws/proxy/config/infra/utils)
- ✅ 删除冗余 .js 编译产物与 re-export shim;LRU O(1);日志 skip 启动期编译
- ✅ 静态资源 safe-path 防穿越;HTTPS 站点 HSTS 响应头
