Compare commits

3 Commits

Author SHA1 Message Date
zg
b131f40410 初始化3 2026-07-16 15:18:56 +08:00
zg
32e8b93a30 初始化3 2026-07-16 15:04:25 +08:00
zg
3710e7866b 初始化2 2026-07-16 13:45:30 +08:00
6 changed files with 117 additions and 23 deletions

View File

@@ -102,7 +102,7 @@ class DnsService:
def list_records(self, domain_zone, rr_keyword=None, record_type=None): def list_records(self, domain_zone, rr_keyword=None, record_type=None):
""" """
获取域名解析记录列表 获取域名解析记录列表(自动分页,拉取全部记录)
Args: Args:
domain_zone: 主域名 (如 zgitm.com) domain_zone: 主域名 (如 zgitm.com)
@@ -112,21 +112,36 @@ class DnsService:
Returns: Returns:
list[dict]: 解析记录列表 list[dict]: 解析记录列表
""" """
params = {'DomainName': domain_zone} params = {
'DomainName': domain_zone,
'PageSize': '100', # 每页最大100条
}
if rr_keyword: if rr_keyword:
params['RRKeyWord'] = rr_keyword params['RRKeyWord'] = rr_keyword
if record_type: if record_type:
params['Type'] = record_type params['Type'] = record_type
all_records = []
page_number = 1
total_count = None
while True:
params['PageNumber'] = str(page_number)
resp = self._call('DescribeDomainRecords', params) resp = self._call('DescribeDomainRecords', params)
records = resp.get('DomainRecords', {}).get('Record', [])
# 统一转列表 domain_records = resp.get('DomainRecords', {})
records = domain_records.get('Record', [])
if total_count is None:
total_count = domain_records.get('TotalCount', 0)
logger.info(f'DNS 记录总数: {total_count}, 开始分页拉取...')
# 统一转列表(单条记录时阿里云返回 dict
if isinstance(records, dict): if isinstance(records, dict):
records = [records] records = [records]
result = []
for r in records: for r in records:
result.append({ all_records.append({
'record_id': r.get('RecordId', ''), 'record_id': r.get('RecordId', ''),
'rr': r.get('RR', ''), 'rr': r.get('RR', ''),
'type': r.get('Type', 'A'), 'type': r.get('Type', 'A'),
@@ -136,7 +151,14 @@ class DnsService:
'status': r.get('Status', 'ENABLE'), 'status': r.get('Status', 'ENABLE'),
'full_domain': (r.get('RR', '') + '.' + domain_zone).strip('.'), 'full_domain': (r.get('RR', '') + '.' + domain_zone).strip('.'),
}) })
return result
# 判断是否还有下一页
if len(all_records) >= total_count or len(records) < 100:
break
page_number += 1
logger.info(f'DNS 记录拉取完成: zone={domain_zone}, 共 {len(all_records)}')
return all_records
def add_record(self, domain_zone, rr, record_type, value, ttl=600): def add_record(self, domain_zone, rr, record_type, value, ttl=600):
""" """

View File

@@ -1,3 +1,4 @@
- [会话 2026-07-16 #1](session-20260716-1.md) — 宝塔API白名单过期排查 + DNS列表分页修复阿里云API默认20→72条
- [会话 2026-06-21 #2](session-20260621-2.md) — DNS解析API从10.1.1.160迁移至101.132.183.138:32210Java后端改指新地址 - [会话 2026-06-21 #2](session-20260621-2.md) — DNS解析API从10.1.1.160迁移至101.132.183.138:32210Java后端改指新地址
- [会话 2026-06-21 #1](session-20260621-1.md) — 宝塔面板API接入Nginx反代管理迁移至宝塔只读160 nginx废弃前端只读改造 - [会话 2026-06-21 #1](session-20260621-1.md) — 宝塔面板API接入Nginx反代管理迁移至宝塔只读160 nginx废弃前端只读改造
- [会话 2026-06-19 #1](session-20260619-1.md) — 审计字段全栈实现:创建人/更新人/时间 + 排序 + DNS本地审计表 + 数据库迁移 + 部署 - [会话 2026-06-19 #1](session-20260619-1.md) — 审计字段全栈实现:创建人/更新人/时间 + 排序 + DNS本地审计表 + 数据库迁移 + 部署

View File

@@ -0,0 +1,70 @@
---
name: session-20260716-1
description: 2026-07-16 第1次会话 — 宝塔API返回HTML排查IP白名单+ DNS列表分页修复20→72条
metadata:
type: session
date: 2026-07-16
sessionNumber: 1
startTime: 2026-07-16T00:00:00+08:00
---
# 2026-07-16 第1次会话
## 会话摘要
排查 `/api/rules` 接口报错问题,确认根因是 10.1.1.170 出公网 IP 发生变化,宝塔面板白名单中仍是旧 IP `183.192.136.97`,导致宝塔拒绝请求返回 HTML 登录页。用户更新白名单后解决。
## 关键操作
### 1. 前端打包命令确认
- **做了什么**: 查看了 `nginx-manager-frontend/package.json`,确认打包命令为 `npm run build`(执行 `vite build`
- **结果**: 无单独的 prod 命令,`build` 默认即生产模式打包,输出到 `dist/` 目录
### 2. 宝塔API /api/rules 报错排查
- **现象**: 前端访问 `https://gw.server.zgitm.com/api/rules` 报错:
```
获取转发规则失败: 宝塔API请求失败: Could not extract response:
no suitable HttpMessageConverter found for response type
[java.util.Map<java.lang.String, java.lang.Object>]
and content type [text/html;charset=utf-8]
```
- **调用链路**: Vue前端 → Gateway → Java后端(10.1.1.170:4002) → btRestTemplate → 宝塔面板(101.132.183.138:18888) → 返回 text/html 而非 JSON
- **排查**: 阅读了 `BTPanelApiClient.java`、`ForwardingRuleService.java`、`ForwardingRuleController.java`、`RestTemplateConfig.java`、`application.yml`,确认代码逻辑没问题
- **根因**: 10.1.1.170 出公网 IP 从 `183.192.136.97` 变成了新 IP宝塔面板白名单拦截请求返回 HTML 登录页
- **解决**: 用户更新宝塔面板 IP 白名单后恢复正常
### 3. 可能原因分析(按可能性排序)
| 排名 | 原因 | 说明 |
|------|------|------|
| 1 | 宝塔面板服务挂了 | 138 上的宝塔面板进程崩溃nginx 返回 HTML 错误页 |
| 2 | API Key 过期/失效 | 宝塔返回登录页 HTML |
| **3** | **IP 白名单变化** ✅ | **确认为此原因** |
| 4 | 宝塔面板端口变更 | 138:18888 端口改了 |
## 重要信息
### 当前架构(无变化)
| 组件 | 机器 | 端口 | 说明 |
|------|------|------|------|
| Vue 前端 | 10.1.1.170 Docker | 3002 | Nginx转发管理/SSL/DNS |
| Java 后端 | 10.1.1.170 Docker | 4002 | 宝塔API接入 + 阿里云DNS |
| DNS Python API | 101.132.183.138 | 32210 | 阿里云DNS解析 |
| 宝塔面板 | 101.132.183.138 | 18888 | Nginx反代管理API Key: ahv5RRcYm3Vi2PzEFvqYsZvsS8LeGkYp |
| MySQL | 10.1.1.122 | 3306 | DNS审计 + 证书通知配置 |
### 宝塔面板连接信息
- 面板地址: https://101.132.183.138:18888
- API Key: ahv5RRcYm3Vi2PzEFvqYsZvsS8LeGkYp
- ⚠️ IP 白名单需要与 10.1.1.170 实际出公网 IP 保持一致
### 4. DNS 记录列表只返回 20 条修复
- **现象**: `GET /api/dns/records?zone=zgitm.com` 只返回 20 条记录
- **调用链路**: Vue前端 → Java后端 → Python DNS API(101.132.183.138:32210) → 阿里云 DescribeDomainRecords API
- **根因**: `dns-api/dns_service.py` 的 `list_records()` 调用阿里云 API 时未传 `PageSize` 参数,默认仅返回 20 条
- **修复**: 新增分页循环逻辑,`PageSize=100`,逐页拉取直到取完全部 `TotalCount` 条
- **改动文件**: `dns-api/dns_service.py` → 已部署到 101.132.183.138:/opt/dns-api/dns_service.py
- **验证**: 修复前 20 条 → 修复后 72 条
- **部署命令**: `scp` 上传 + `systemctl restart dns-api`138 SSH 已免密)
## 改进建议
- [ ] 考虑添加健康检查端点,主动监控宝塔 API 连通性
- [ ] 考虑在 `BTPanelApiClient` 中增加响应 Content-Type 检测,当返回 HTML 时给出更友好的错误提示(而非 `HttpMessageConverter` 的底层错误)

View File

@@ -2,4 +2,5 @@ FROM harbor.zgitm.com/library/eclipse-temurin:17-jre
WORKDIR /app WORKDIR /app
COPY target/*.jar app.jar COPY target/*.jar app.jar
EXPOSE 32402 EXPOSE 32402
ENTRYPOINT ["java","-jar","app.jar"] #ENTRYPOINT ["java","-jar","app.jar"]
ENTRYPOINT ["java","-Xms256m","-Xmx512m","-XX:+UseG1GC","-XX:MaxGCPauseMillis=200","-XX:+HeapDumpOnOutOfMemoryError","-XX:HeapDumpPath=/app/dump.hprof","-Djava.security.egd=file:/dev/./urandom","-Duser.timezone=Asia/Shanghai","-jar","app.jar"]

View File

@@ -5,7 +5,7 @@
# ========================================== # ==========================================
spring: spring:
datasource: datasource:
url: jdbc:mysql://10.1.1.122:3306/nginxserver?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true url: jdbc:mysql://10.20.1.122:3306/nginxserver?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: nginxserver username: nginxserver
password: mokee. password: mokee.
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver

View File

@@ -5,7 +5,7 @@
# ========================================== # ==========================================
spring: spring:
datasource: datasource:
url: jdbc:mysql://10.1.1.122:3306/nginxserver?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true url: jdbc:mysql://10.20.1.122:3306/nginxserver?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
username: nginxserver username: nginxserver
password: mokee. password: mokee.
driver-class-name: com.mysql.cj.jdbc.Driver driver-class-name: com.mysql.cj.jdbc.Driver