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

asai-nodejs-host

v0.2.42

Published

asai for you

Readme

asai-nodejs-host — HTTP/WebSocket 服务器主机插件

功能概述

asai-nodejs-host 是系统的核心服务器引擎,基于 Node.js 原生 http/httpsws 库,负责:

  • 多站点 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.defaulthosts.<站点名> 浅合并;代理同理 = 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 证书 |

站点 httptypehttps:// 时,优先用站点级 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'));

注意事项

  1. 处理器通过模块级 workHandlers Map 注册,不污染 global
  2. validateHostdir() 拒绝 default / asai 作为普通站点名启动。
  3. 静态路径经 resolvePathUnderRoots 白名单校验,拒绝目录穿越;代理默认不透传 Userinfo。
  4. HTTP 连接监控间隔 5 分钟;超 95% 清理空闲 5 分钟以上连接。
  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 响应头