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

177 lines
7.4 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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 |
| `GET /t/prescription` | 本地 | 处方业务记录PDF / 在线处方 / 处方核销,支持详情与单条重试) |
转发规则:
- **URL**由环境变量固定Scheme/Host/Path不使用客户端 URL。
- **Body**:原样透传。
- **Header**:仅白名单内的业务头透传到政务云;`User-Agent``Cookie``X-Forwarded-*``X-Forward-Token` 等不会带上游。
- 监管白名单含 `requestBody``X-Ca-Signature` 等(与 transit `hy.BuildUpload` 一致)。
## 环境配置
```bash
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`,便于联调核对将要发出的报文。
响应示例:
```json
{
"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`
本地排查示例:
```env
ENABLE_FORWARD=false
ALLOW_IPS=
```
## 运行
```bash
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`](d:/worker/code/xk-hy-forward-go/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` 中设置:
```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`(同时输出控制台),格式:
```text
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在**程序同级目录**写入独立文件:
```text
{程序目录}/api-logs/2026-05-27 14/20260527143015_supervise_a1b2c3d4.log
```
单文件固定 **三段**(完整原文,不脱敏):
```text
=== 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-Authorization``X-Forward-Token`、业务密文及 PDF已加入 `.gitignore`,请勿提交仓库或暴露到外网。