xk-hy-forward-go
内网双通道转发:外网 xk-hy-transit-go 只访问本服务,由本机转发至浙江省政务云(59.202.52.129)。
架构
| 监听路径 | 转发目标 | 用途 |
|---|---|---|
POST /province/supervise/data |
SUPERVISE_TARGET_URL(28212) |
加密后的监管业务 JSON |
POST /mng/file/auth/upload |
FILE_TARGET_URL(28211) |
处方 PDF multipart 上传 |
GET /health |
本地 | 健康检查 |
GET /t |
本地 | 政务云测试页(读 file api-logs、连通测试、回放、导出 ApiPost) |
转发规则:
- URL:由环境变量固定(Scheme/Host/Path),不使用客户端 URL。
- Body:原样透传。
- Header:仅白名单内的业务头透传到政务云;
User-Agent、Cookie、X-Forwarded-*、X-Forward-Token等不会带上游。 - 监管白名单含
requestBody、X-Ca-Signature等(与 transithy.BuildUpload一致)。
环境配置
cp .env.example .env
# 编辑 .env 后,建议在项目根目录启动(见下方「启动与 .env 加载」)
启动与 .env 加载
程序启动时会按以下顺序查找并加载 第一个存在的 .env 文件:
- 当前工作目录(
os.Getwd()) - 可执行文件所在目录
- 可执行文件上级目录
加载成功时控制台会输出:[forward] 已加载 /path/to/.env。若未找到任何 .env,会提示使用环境变量或代码默认值。
注意:
- 请使用
#作为注释(不要用;,godotenv 不会把;行当作注释)。 - 从 IDE / 服务方式启动时,请把 Working Directory 设为
xk-hy-forward-go项目根,或把.env放在 exe 同目录。 - 核对启动日志中的
forward_enabled=、supervise=、file=是否为你在.env里配置的项。
| 变量 | 默认 | 说明 |
|---|---|---|
LISTEN_ADDR |
:16001 |
监听地址(建议绑内网 IP) |
SUPERVISE_TARGET_URL |
政务云 28212 | 监管业务上报 |
FILE_TARGET_URL |
政务云 28211 | 处方 PDF 上传 |
TARGET_URL |
(兼容) | 未设 SUPERVISE_TARGET_URL 时生效 |
ALLOW_IPS |
空 | 逗号分隔来源 IP;生产建议填 transit 出口 IP |
FORWARD_SHARED_SECRET |
空 | 非空时要求请求头 X-Forward-Token 一致(与 transit .env 同值) |
ENABLE_FORWARD |
true |
是否真正转发到政务云;false/0/no 时进入回显模式(见下) |
LOG_DIR |
空 | 日志根目录;默认 {程序目录}/../log/forward/ |
回显模式(ENABLE_FORWARD=false)
不请求政务云上游,按与真实转发相同规则(固定目标 URL + Header 白名单 + 原样 Body)组装出站内容,以 JSON 返回给 xk-hy-transit-go,便于联调核对将要发出的报文。
响应示例:
{
"dry_run": true,
"kind": "supervise",
"target_url": "https://59.202.52.129:28212/province/supervise/data",
"method": "POST",
"headers": { "Content-Type": ["application/json"], "X-Ca-Signature": ["..."] },
"body": "明文(监管 JSON 且 UTF-8 有效时)",
"body_base64": "始终提供,可还原 multipart/二进制"
}
headers:过滤后将要转发的请求头。body:明文;kind=file或multipart时为空,请用body_base64。- 启动日志含
forward_enabled=false;应用日志行为dry_run | target=... | body_len=N。
本地排查示例:
ENABLE_FORWARD=false
ALLOW_IPS=
运行
cd xk-hy-forward-go
go run main.go
go test ./...
main.go 仅作入口,业务逻辑在 internal/forward 包;go run main.go 会编译入口及其依赖,启动全部路由(/health、监管、文件上传)。等价方式:go run .、go build -o forward.exe .。
Windows 也可双击或执行项目根目录下的 run.bat(内部为 go run main.go)。
IDE 调试:Working Directory 设为项目根,运行文件选 main.go 即可。
政务云测试页 /t
启动后浏览器访问:http://<forward-host>:16001/t(随 forward 进程开放,仅建议内网使用)。
功能:
- 连通测试:对当前
.env中 28212 / 28211 目标 URL 发起探测。 - file 日志:左侧列出
api-logs/**/_file_*.log,点击解析 入站(块1) / 出站(块2) 的 Headers 与 Body(multipart 为body_base64)。 - 发送:按出站头/体向政务云回放 POST(不含
X-Forward-Token)。 - 导出 ApiPost:下载 Postman Collection v2.1 JSON,在 ApiPost 中选择 导入 → Postman 集合。
日志含 X-Authorization 等敏感信息,请勿将导出的集合或 /t 暴露到公网。
本地联调 mock 上游时,在 .env 中设置:
SUPERVISE_TARGET_URL=http://127.0.0.1:18001/api/
FILE_TARGET_URL=http://127.0.0.1:18001/api/u
未配置 SUPERVISE_TARGET_URL / FILE_TARGET_URL 时,代码默认指向政务云 59.202.52.129(与 .env.example 一致)。
应用日志
每条转发写入 app-YYYY-MM-DD.log(同时输出控制台),格式:
2026-05-19T22:00:01+08:00 | 192.168.1.20 | supervise | http=200 | 120ms | https://59.202.52.129:28212/...
2026-05-19T22:00:02+08:00 | 192.168.1.20 | supervise | dry_run | target=https://... | body_len=1024 | 3ms
摘要行不含完整 body;明细见下方 API 请求日志。
API 请求日志(api-logs)
每次 HTTP 请求(含 /health、监管、文件上传、403 本地拒绝、dry-run)在程序同级目录写入独立文件:
{程序目录}/api-logs/2026-05-27 14/20260527143015_supervise_a1b2c3d4.log
单文件固定 三段(完整原文,不脱敏):
=== META ===
Time / ClientIP / Path / Kind(supervise|file) / DurationMs / Status
=== 1. 入站请求(transit → forward)===
URL、原始 Headers(含 X-Forward-Token)、Body(multipart/PDF 为 body_len + body_base64)
=== 2. 出站转发(forward → 政务云)===
TargetURL、白名单过滤后 Headers、Body(与入站相同字节)
=== 3. 回复(政务云 → forward → transit)===
UpstreamStatus、UpstreamHeaders、Body;JSON 响应额外输出 BodyJSON(缩进格式化)
排查超时:若 块1+块2 完整、块3 为空且 DurationMs 很大,说明已发往政务云但上游无响应(常见为 28211 网络不通)。
注意:日志含 X-Authorization、X-Forward-Token、业务密文及 PDF,已加入 .gitignore,请勿提交仓库或暴露到外网。