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

websocket-proxy-http-request

v0.0.7

Published

通过WebSocket将外网流量转发到内网服务

Readme

WebSocket Proxy HTTP Request

Node.js TypeScript License Status

通过WebSocket将外网HTTP流量转发到内网服务的高性能代理工具。

✨ 特性

  • 🚀 高性能: P99延迟30ms,RPS达629
  • 🔄 自动重连: 断线自动恢复,最多重试3次
  • 💓 心跳保活: 30秒心跳间隔,保持连接稳定
  • 🔐 安全认证: 支持Token认证(可选)
  • 📊 完整日志: 请求全链路可追踪
  • 🎯 类型安全: TypeScript完整类型定义
  • 🛠️ 易于部署: 支持PM2和Docker

📖 快速开始

方式一:使用 npx(推荐)

无需安装,直接运行:

# 1. 克隆项目
git clone <repository-url>
cd websocket-proxy-http-request

# 2. 编译项目
npm install
npm run build

# 3. 启动代理服务器(外网)
npx ws-proxy-server
# 或
npx ws-proxy proxy-server

# 4. 启动客户端代理(内网,新终端)
npx ws-client-agent
# 或
npx ws-proxy client-agent

方式二:本地安装

# 安装依赖
npm install

# 编译
npm run build

配置

创建 .env.proxy (代理服务器):

PROXY_PORT=8080
WS_PORT=8081
AUTH_ENABLED=false
LOG_LEVEL=info

创建 .env.client (客户端):

PROXY_WS_URL=ws://localhost:8081
LOCAL_TARGET_HOST=localhost
LOCAL_TARGET_PORT=3000
CLIENT_ID=client-001

启动

使用 npx(推荐)

# 启动代理服务器(外网机器)
npx ws-proxy-server
# 或使用子命令
npx ws-proxy proxy-server

# 启动客户端(内网机器,新终端)
npx ws-client-agent
# 或使用子命令
npx ws-proxy client-agent

使用 npm scripts

# 编译
npm run build

# 启动代理服务器(外网机器)
npm run start:proxy

# 启动客户端(内网机器)
npm run start:client

直接运行

# 编译
npm run build

# 启动代理服务器(外网机器)
node dist/src/proxy-server.js

# 启动客户端(内网机器)
node dist/src/client-agent.js

测试

使用自定义动态装箱/拆箱方式发送请求:

# GET请求示例(带查询参数)
curl -X POST http://localhost:8080/proxy \
  -H "Content-Type: application/json" \
  -d '{
    "url": "http://localhost:9000/api/users",
    "method": "get",
    "params": {"name": "allen"}
  }'

# POST请求示例
curl -X POST http://localhost:8080/proxy \
  -H "Content-Type: application/json" \
  -d '{
    "url": "http://localhost:9000/api/users",
    "method": "post",
    "body": {"name": "allen", "age": 25}
  }'

# 指定特定客户端(clientId路由)
curl -X POST http://localhost:8080/proxy \
  -H "Content-Type: application/json" \
  -d '{
    "url": "http://localhost:9000/api/users",
    "method": "get",
    "clientId": "client-001"
  }'

请求参数

  • url (必需): 内网服务器的完整URL
  • method (必需): HTTP方法(get/post/put/delete等)
  • params (可选): URL查询参数对象,自动序列化为查询字符串
  • body (可选): 请求体,用于POST/PUT等方法
  • clientId (可选): 指定客户端ID,将请求路由到特定客户端。如果不指定,将使用第一个可用客户端

按客户端 ID 路径代理

除了 POST /proxy 装箱接口,代理服务器也支持直接使用客户端 ID 作为路径前缀。该路由与 WebSocket 共用 WS_PORT,例如 1315

GET  http://170.106.115.192:1315/client-001/       -> client 本地目标服务 /
GET  http://170.106.115.192:1315/client-001/aa     -> client 本地目标服务 /aa
POST http://170.106.115.192:1315/client-001/api/users -> client 本地目标服务 /api/users

client 的 .env.client 决定本地目标服务:

PROXY_WS_URL=ws://170.106.115.192:1315
LOCAL_TARGET_HOST=host.docker.internal
LOCAL_TARGET_PORT=3000
CLIENT_ID=client-001

调用示例:

curl http://170.106.115.192:1315/client-001/health

curl -X POST http://170.106.115.192:1315/client-001/api/users \
  -H "Content-Type: application/json" \
  -d '{"name":"allen","age":25}'

路径中的 client-001 必须与 client 注册时的 CLIENT_ID 一致。GET、POST、PUT、PATCH、DELETE 等 HTTP 方法都会按同样的路径规则转发;原有 POST /proxy 接口仍然保留。

健康检查

# 检查服务器状态
curl http://localhost:8080/health

# 响应包含服务器状态、客户端连接信息、内存使用等

🏗️ 架构

外网HTTP请求 (8080端口)
    ↓
Proxy Server (装箱)
    ↓
WebSocket 传输 (8081端口)
    ↓
Client Agent (拆箱)
    ↓
内网HTTP请求 (3000端口)
    ↓
响应原路返回

📊 性能指标

| 指标 | 数值 | 评级 | |------|------|------| | 平均响应时间 | 3.42ms | ⭐⭐⭐⭐⭐ | | P99延迟 | 30ms | ⭐⭐⭐⭐⭐ | | 吞吐量(RPS) | 629 | ⭐⭐⭐⭐⭐ | | 并发处理 | 50+ | ⭐⭐⭐⭐⭐ | | 请求成功率 | 100% | ⭐⭐⭐⭐⭐ |

🎯 核心功能

✅ 已实现

  • [x] HTTP请求代理(所有方法)
  • [x] WebSocket双向通信
  • [x] 请求装箱/拆箱
  • [x] 响应原路返回
  • [x] 请求超时控制(30秒)
  • [x] 心跳保活机制(30秒)
  • [x] 断线自动重连(3次)
  • [x] Token认证(可选)
  • [x] 完整日志系统
  • [x] 健康检查接口
  • [x] 连接数统计

📁 项目结构

websocket-proxy-http-request/
├── src/
│   ├── proxy-server.ts          # 代理服务器(核心)
│   ├── client-agent.ts          # 客户端代理(核心)
│   ├── types/                   # TypeScript类型
│   │   ├── protocol.ts          # 消息协议
│   │   └── config.ts            # 配置类型
│   ├── config/                  # 配置管理
│   │   ├── proxy-server.config.ts
│   │   ├── client-agent.config.ts
│   │   └── logger.config.ts
│   └── utils/                   # 工具函数
│       ├── logger.ts            # 日志管理
│       └── id-generator.ts      # ID生成
├── mock/                        # Mock测试服务
├── test-client.js               # 功能测试
├── test-performance.js          # 性能测试
└── dist/                        # 编译输出

🔧 配置说明

代理服务器配置

| 配置项 | 说明 | 默认值 | |--------|------|--------| | PROXY_PORT | HTTP代理端口 | 8080 | | WS_PORT | WebSocket端口 | 8081 | | AUTH_ENABLED | 是否启用认证 | false | | REQUEST_TIMEOUT | 请求超时(ms) | 30000 | | HEARTBEAT_INTERVAL | 心跳间隔(ms) | 30000 |

客户端配置

| 配置项 | 说明 | 默认值 | |--------|------|--------| | PROXY_WS_URL | 代理服务器地址 | ws://localhost:8081 | | LOCAL_TARGET_HOST | 内网目标主机 | localhost | | LOCAL_TARGET_PORT | 内网目标端口 | 3000 | | CLIENT_ID | 客户端标识 | client-001 | | RECONNECT_ENABLED | 自动重连 | true |

🧪 测试

功能测试

# 运行完整功能测试
node test-client.js

# 结果:11/11 测试通过 ✅

性能测试

# 运行性能测试
node test-performance.js

# 结果:
# - 平均响应时间: 3.42ms
# - P99延迟: 30ms
# - 吞吐量: 629 RPS

🚀 部署

使用PM2

# 安装PM2
npm install -g pm2

# 启动服务
pm2 start dist/src/proxy-server.js --name proxy-server
pm2 start dist/src/client-agent.js --name client-agent

# 查看状态
pm2 status

# 查看日志
pm2 logs

使用Docker

项目提供两个独立镜像:server 负责 HTTP 代理和 WebSocket 服务,client 负责连接 server 并访问内网目标服务。

1. 准备配置文件

在项目根目录创建 .env.proxy。该文件只在运行时注入,不会被 Dockerfile 复制进镜像:

PROXY_PORT=8080
WS_PORT=8081
AUTH_ENABLED=true
AUTH_TOKEN=replace-with-a-long-random-token
LOG_LEVEL=warn
LOG_TO_FILE=false

创建 .env.client

PROXY_WS_URL=ws://your-server-host:8081
AUTH_TOKEN=replace-with-the-same-token
LOCAL_TARGET_HOST=host.docker.internal
LOCAL_TARGET_PORT=3000
CLIENT_ID=client-001

AUTH_TOKEN 必须使用随机长字符串,且 server/client 两端保持一致。不要把真实 token 提交到 Git 或写入 Dockerfile。

2. 构建镜像

docker build --pull -f Dockerfile.server -t websocket-proxy-server:local .
docker build --pull -f Dockerfile.client -t websocket-proxy-client:local .

3. 启动 server

docker run -d --name websocket-proxy-server \
  --restart unless-stopped \
  --env-file .env.proxy \
  -p 8080:8080 \
  -p 8081:8081 \
  websocket-proxy-server:local

验证 server:

curl http://127.0.0.1:8080/health
docker logs --tail 100 websocket-proxy-server

4. 启动 client

docker run -d --name websocket-proxy-client \
  --restart unless-stopped \
  --env-file .env.client \
  websocket-proxy-client:local

验证 client 是否已连接:

docker logs --tail 100 websocket-proxy-client
curl http://127.0.0.1:8080/health

如果 client 访问的是 Linux 宿主机上的服务,需要额外增加:

--add-host host.docker.internal:host-gateway

然后将 LOCAL_TARGET_HOST 设置为 host.docker.internal。如果目标服务也运行在 Docker 中,建议把 server、client 和目标服务加入同一个用户自定义 Docker network,并使用目标容器名访问,不要使用 --network host 绕过网络隔离。

停止和删除容器:

docker stop websocket-proxy-client websocket-proxy-server
docker rm websocket-proxy-client websocket-proxy-server

发布到 Docker Hub

当前镜像构建和 server/client 互联已经验证,但本项目当前不适合直接以“生产就绪”的 latest 标签公开发布:本次 npm audit --omit=dev --audit-level=high 检测到 4 个 high 和 4 个 moderate 漏洞,且 axiosws 等依赖存在可用修复版本。建议先完成依赖修复,再发布公开稳定标签。

发布前检查

npm audit --omit=dev --audit-level=high
npm audit fix
npm run build

依赖升级后必须重新运行功能测试和 Docker 构建;如果审计仍有 high/critical 漏洞,不要发布 latest,可以先发布私有仓库或带明确 -dev / -rc 后缀的测试标签。

创建仓库并登录

建议在 Docker Hub 创建两个仓库:

  • websocket-proxy-server
  • websocket-proxy-client

登录时使用 Docker Hub Access Token,不要在命令行直接写密码:

docker login --username YOUR_DOCKERHUB_USERNAME

CI 环境可使用 --password-stdin,并通过 CI Secret 注入 token:

printf '%s' "$DOCKERHUB_TOKEN" | docker login \
  --username "$DOCKERHUB_USERNAME" \
  --password-stdin

构建并推送版本标签

YOUR_DOCKERHUB_USERNAME 替换为 Docker Hub 用户名,将 0.0.4 替换为实际发布版本:

export DOCKERHUB_USERNAME=YOUR_DOCKERHUB_USERNAME
export IMAGE_VERSION=0.0.4

docker build --pull -f Dockerfile.server \
  -t "$DOCKERHUB_USERNAME/websocket-proxy-server:$IMAGE_VERSION" \
  -t "$DOCKERHUB_USERNAME/websocket-proxy-server:latest" .

docker build --pull -f Dockerfile.client \
  -t "$DOCKERHUB_USERNAME/websocket-proxy-client:$IMAGE_VERSION" \
  -t "$DOCKERHUB_USERNAME/websocket-proxy-client:latest" .

docker push "$DOCKERHUB_USERNAME/websocket-proxy-server:$IMAGE_VERSION"
docker push "$DOCKERHUB_USERNAME/websocket-proxy-server:latest"
docker push "$DOCKERHUB_USERNAME/websocket-proxy-client:$IMAGE_VERSION"
docker push "$DOCKERHUB_USERNAME/websocket-proxy-client:latest"

生产部署应固定版本标签,不要只依赖 latest

docker pull "$DOCKERHUB_USERNAME/websocket-proxy-server:$IMAGE_VERSION"
docker pull "$DOCKERHUB_USERNAME/websocket-proxy-client:$IMAGE_VERSION"
docker image inspect \
  "$DOCKERHUB_USERNAME/websocket-proxy-server:$IMAGE_VERSION" \
  "$DOCKERHUB_USERNAME/websocket-proxy-client:$IMAGE_VERSION"

# 登录 Docker Hub 后执行镜像 CVE/SBOM 检查
docker scout cves "$DOCKERHUB_USERNAME/websocket-proxy-server:$IMAGE_VERSION"
docker scout cves "$DOCKERHUB_USERNAME/websocket-proxy-client:$IMAGE_VERSION"
docker scout sbom "$DOCKERHUB_USERNAME/websocket-proxy-server:$IMAGE_VERSION"

多架构发布可以将 docker build 替换为 docker buildx build --platform linux/amd64,linux/arm64 --push,并同时指定版本标签和 latest 标签。

Docker 官方命令参考:docker logindocker pushDocker Hub repositories

Docker Hub 发布安全检查

镜像层面的安全措施:

  • 两个运行时镜像使用 nodejs 非 root 用户。
  • .dockerignore 排除了 .env.history、日志、测试和文档;运行时只复制 dist、生产依赖和包元数据。
  • 当前构建检查未发现 .env、私钥或 token 文件进入镜像。
  • Dockerfile 不包含认证 token;配置应通过 --env-file、环境变量或 Secret 注入。

仍需由部署方承担的风险:

  • AUTH_ENABLED 默认是 false;当前认证只保护 WebSocket client 注册,/proxy/health/:clientId/* 没有 HTTP 认证。公网部署必须在反向代理、API Gateway 或防火墙层限制访问。
  • client 会按请求中的完整 URL 发起内网 HTTP 请求。未经限制时,任何能调用 /proxy 的人都可能借此访问 client 网络可达的内网、云元数据或管理接口,属于 SSRF/横向访问风险。生产环境应使用网络出口控制和目标 URL allowlist;当前代码尚未实现 allowlist。
  • 默认使用明文 http://ws://。跨公网传输必须放在 HTTPS/WSS 反向代理、VPN 或私有网络内,不能直接暴露 8080/8081。
  • server/client 会把 URL、请求头、请求体和响应信息写入控制台或日志,可能泄露 Authorization、Cookie 和业务数据。生产环境应避免敏感字段,并保护容器日志;LOG_TO_FILE=false 不能关闭源码中的 console.log
  • 当前没有 HTTP rate limit;WebSocket 也没有显式的消息大小上限,公网部署应增加网关限流和连接限制。
  • node:20-alpine 使用可变 tag。正式供应链要求应固定基础镜像 digest,并在 CI 中执行镜像 CVE/SBOM 扫描。

因此,当前结论是:适合发布为经过说明的开发/测试镜像或私有镜像;不建议在依赖审计和公网访问控制完成前,把它作为生产就绪的公开 latest 镜像。

📚 文档

🎓 技术栈

  • 运行时: Node.js 18+
  • 语言: TypeScript 5.3+
  • WebSocket: ws 8.16+
  • HTTP服务: Express 4.18+
  • HTTP客户端: Axios 1.6+
  • 日志: Winston 3.11+

🔍 监控

健康检查

curl http://localhost:8080/health

# 返回:
{
  "status": "ok",
  "clients": 1,
  "pendingRequests": 0
}

日志

# 查看日志
tail -f logs/app.log

# 查看错误日志
tail -f logs/error.log

💡 使用场景

  1. 远程开发: 在家访问公司内网开发环境
  2. 临时演示: 将内网测试环境暴露给客户
  3. 跨网络调试: 调试不同网络的服务
  4. 内网穿透: 将内网服务暴露到公网

🤝 贡献

欢迎提交Issue和Pull Request!

📄 许可证

MIT License

🎉 项目状态

  • 功能完整: 所有核心和辅助功能已实现
  • 测试通过: 11项功能测试 + 4项性能测试全部通过
  • 性能优秀: P99延迟30ms,RPS达629
  • 文档完善: 6份完整文档
  • ⚠️ 发布状态: Docker 镜像可构建;公开生产发布需先完成依赖审计和网络访问控制

📞 联系方式

如有问题或建议,欢迎反馈!


⭐ 如果这个项目对你有帮助,请给个Star!