Files
xk-hy-forward-go/README.md
2026-07-21 16:35:46 +08:00

7.4 KiB
Raw Blame History

xk-hy-forward-go

内网双通道转发:外网 xk-hy-transit-go 只访问本服务,由本机转发至浙江省政务云(59.202.52.129)。

架构

监听路径 转发目标 用途
POST /province/supervise/data SUPERVISE_TARGET_URL28212 加密后的监管业务 JSON
POST /mng/file/auth/upload FILE_TARGET_URL28211 处方 PDF multipart 上传
GET /health 本地 健康检查
GET /t 本地 政务云测试页(读 file api-logs、连通测试、回放、导出 ApiPost
GET /t/prescription 本地 处方业务记录PDF / 在线处方 / 处方核销,支持详情与单条重试)

转发规则:

  • URL由环境变量固定Scheme/Host/Path不使用客户端 URL。
  • Body:原样透传。
  • Header:仅白名单内的业务头透传到政务云;User-AgentCookieX-Forwarded-*X-Forward-Token 等不会带上游。
  • 监管白名单含 requestBodyX-Ca-Signature 等(与 transit hy.BuildUpload 一致)。

环境配置

cp .env.example .env
# 编辑 .env 后,建议在项目根目录启动(见下方「启动与 .env 加载」)

启动与 .env 加载

程序启动时会按以下顺序查找并加载 第一个存在的 .env 文件:

  1. 当前工作目录(os.Getwd()
  2. 可执行文件所在目录
  3. 可执行文件上级目录

加载成功时控制台会输出:[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=filemultipart 时为空,请用 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 与 Bodymultipart 为 body_base64)。
  • 发送:按出站头/体向政务云回放 POST不含 X-Forward-Token)。
  • 导出 ApiPost:下载 Postman Collection v2.1 JSON在 ApiPost 中选择 导入 → Postman 集合

日志含 X-Authorization 等敏感信息,请勿将导出的集合或 /t 暴露到公网。

处方业务记录 /t/prescription

访问:http://<forward-host>:16001/t/prescription

每次写 api-log 后,若为处方相关业务,会追加一行到 {api-logs}/prescription-audit.jsonl

bizType 含义
pdf 28211 处方 PDF 上传
recipe 28212 uploadRecipeIndicators 在线处方
verification 28212 uploadRecipeVerificationIndicators 处方核销

页面三栏切换查看记录,支持 详情api-log 三段 JSON重试(出站块 2 回放政务云,不更新 transit/xk-api 状态)。

历史日志可点 重建索引POST /t/api/prescription/rebuild)全量扫描 *_file_*.log*_supervise_*.log

/t/api/logs/detail/t/api/test/send 已支持 supervise 日志 rel 路径。

本地联调 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、Bodymultipart/PDF 为 body_len + body_base64

=== 2. 出站转发forward → 政务云)===
TargetURL、白名单过滤后 Headers、Body与入站相同字节

=== 3. 回复(政务云 → forward → transit===
UpstreamStatus、UpstreamHeaders、BodyJSON 响应额外输出 BodyJSON缩进格式化

排查超时:若 块1+块2 完整、块3 为空且 DurationMs 很大,说明已发往政务云但上游无响应(常见为 28211 网络不通)。

注意:日志含 X-AuthorizationX-Forward-Token、业务密文及 PDF已加入 .gitignore,请勿提交仓库或暴露到外网。