# 故障排查(给 AI 助手读) > **把这份文件交给你的 AI 助手,让它按步骤处理。** > 本文件是给**AI** 读的,不是给人读的:不解释原理、不给截图、不让人"打开某个菜单看看"。 > 每一节都是「触发条件 → 可执行的检查 → 结果对应的处置」。 > > 适用范围:**中国大陆网络下,某个预警源连不上、数据不更新、或提醒不响**。 > 本机开发环境的出口在日本,大陆可达性无法事先验证,所以这份文档不猜"哪个域名被墙", > 只让你用可执行的检查**分类**,再选正确的处置。 适用版本:dsh-quake-alert **0.4.1**。文档里的 `http://127.0.0.1:3080` 是 DSH 默认 Web 端口, 若用户改过端口,用实际端口替换(可从 `dsh web` 的启动输出或浏览器地址栏读到)。 --- ## 0. 先确定影响范围(永远从这一步开始) 本插件的五个源走**不同域名、不同通道**,互不牵连。不要笼统回答"连不上"。 | 链路 | 通道 | 域名 | |---|---|---| | 日本 地震 / EEW / 海啸 | WebSocket(浏览器直连) | `api.p2pquake.net` | | 日本 气象灾害(泥石流 / 洪水 / 大雨 / 高潮) | Host 轮询 feed | `www.data.jma.go.jp` | | 全球 地震(实时) | WebSocket(浏览器直连) | `www.seismicportal.eu` | | 全球 地震(目录,含修订) | Host 轮询 feed | `earthquake.usgs.gov` | | 全球 海啸 | Host 轮询 feed | `www.tsunami.gov` | **要交付给用户的结论必须长这样**:「日本地震与 EEW 正常;日本气象灾害的源在当前网络不可达, 这不是你能修的,影响范围是泥石流 / 洪水 / 大雨 / 高潮这四类」。 --- ## 1. 读 Host 侧的健康计数(最快、最准的一步) Host 半边为每个轮询源维护健康计数,通过本地只读路由暴露。 ### 检查 ```sh curl -s "http://127.0.0.1:3080/dsh-quake-alert/feed?source=jma&since=tail&stats=1" curl -s "http://127.0.0.1:3080/dsh-quake-alert/feed?source=usgs&since=tail&stats=1" curl -s "http://127.0.0.1:3080/dsh-quake-alert/feed?source=noaa&since=tail&stats=1" ``` (`source` 只能是 `jma` / `usgs` / `noaa`;写错会返回 `400 {"error":"unknown source"}`——这是 0.4.1 起的行为, **不会**静默退回 jma。) Win32 上没有 curl 时用 PowerShell: ```powershell Invoke-RestMethod "http://127.0.0.1:3080/dsh-quake-alert/feed?source=jma&since=tail&stats=1" | ConvertTo-Json -Depth 5 ``` ### 读结果的对照表 响应形如 `{ "source": "jma", "cursor": …, "entries": [], "stats": { … } }`。**只看 `stats`**: | 现象 | 分类 | 处置 | |---|---|---| | 命令本身失败 / 连接被拒 | DSH 没在跑,或端口不对 | 让用户确认 `dsh web` 正在运行并核对端口。若换了端口,本节所有 URL 都要换 | | `stats.polls === 0` 且 `stats.idleSkips` 在涨 | **按需轮询在节流**(10 分钟内没有浏览器页面读 `/feed`) | 打开 DSH 页面(插件会每 15 秒读一次),等 10–20 秒再查 | | `stats.errors` 持续增长、`stats.lastPollAt` 不再前进 | **不可达 / 握手被中断**(第 2 节继续定位) | 见第 2 节 | | `stats.errors` 为 0,`stats.lastPollAt` 在前进,`stats.feedEntries` 正常 | 链路正常 | **不要报故障。** `feedEntries` 里大多数电文与本插件无关(天气预报等),`received` 少是正常的 | | `stats.stale === true` | **上游数据停更**(源在响应,但给的是旧数据) | 不可降级。如实说明,等上游恢复 | | `stats.detailDropped > 0` | 详情电文反复抓取失败后已放弃 | 说明"有几条电文没取到",并检查第 2 节 | | `stats.lastError` 非空 | 最近一次失败的原因(含 `HTTP 4xx/5xx`、`ECONNRESET`、`响应体过大` 等) | 按关键字对照第 2 节 | > `stats` 里的 `cursor` / `dropped` / `seenSize` / `bufferSize` 是内部游标与环缓冲状态, > 只在判断"是否有增量缺口"时用,不要拿来当故障证据。 --- ## 2. 判断"是网络不可达,还是源/中间层的问题" ### 2.1 本机能不能直达源站 ```sh curl -sS -m 20 -o /dev/null -w 'jma %{http_code} %{time_total}s\n' https://www.data.jma.go.jp/developer/xml/feed/extra.xml curl -sS -m 20 -o /dev/null -w 'usgs %{http_code} %{time_total}s\n' https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/2.5_day.geojson curl -sS -m 20 -o /dev/null -w 'noaa %{http_code} %{time_total}s\n' https://www.tsunami.gov/events/xml/PHEBAtom.xml ``` (Windows 用 `curl.exe`,Win10 1803+ 自带;或 `Invoke-WebRequest -TimeoutSec 20`。) | 结果 | 分类 | 处置 | |---|---|---| | `200`,几百毫秒内 | 本机能直达 | 问题在 Host 侧(回第 1 节看 `stats.lastError`),或只是节流 | | 卡住到超时(`28` / `Operation timed out`) | **连接被丢包 / 阻断** | 不可降级。见第 3 节的影响说明 | | `Connection reset by peer`(`56`) | **连接被重置**(典型的 SNI / 中间设备行为) | 同上 | | `Could not resolve host`(`6`) | **DNS 失败** | 先修 DNS:`nslookup www.data.jma.go.jp`、换公共 DNS 后重试 | | `403` / `429` | **被限流 / 封禁** | 不要自动重试。JMA 因重复下载封 IP,插件的架构已防(Host 单点 + 不重复获取),若仍 403 请停手并如实告知 | | `200` 但内容是 HTML | **响应被替换成拦截页** | 插件会把它判为"数据格式异常"(蓝点)。不要建议关闭证书校验 | ### 2.2 DNS 与 TLS 的分层确认 ```sh nslookup www.data.jma.go.jp curl -v -m 20 https://www.data.jma.go.jp/developer/xml/feed/extra.xml 2>&1 | head -40 ``` - `nslookup` 给不出地址、或给出明显异常地址 → **DNS 层**问题。 - 地址正常、`curl -v` 停在 `TLS handshake` / `Client hello` → **TLS 被中断**。 - 地址正常、TLS 完成、但响应码/内容不对 → **源侧或中间层改写**(第 2.1 节的 403/HTML 两类)。 --- ## 3. 处置:能降级的降级,不能降级的如实说 **在给出建议前,先确认这条降级路径在当前版本确实可用**——不要建议尚未实现的能力。 ### 3.1 现在就能用的:天然降级(分链路说明) 八个源互不牵连,所以正确回答是**逐条说明**: - `api.p2pquake.net`(日本地震 / EEW / 海啸)不可达 → **日本的地震与 EEW 全没了**,这是最严重的一种; 明确告知,不要淡化。 - `www.data.jma.go.jp`(日本气象灾害)不可达 → 地震 / EEW / 海啸仍然正常;受影响的是 泥石流 / 洪水 / 大雨 / 高潮这四类。 - `earthquake.usgs.gov` 不可达 → EMSC 的实时推送可能仍然正常(不同域名);USGS 的**修订版**会缺。 - `www.tsunami.gov` 不可达 → 全球海啸完全没有;日本海啸(P2PQuake)不受影响。 - `www.seismicportal.eu` 不可达 → 全球地震只剩 USGS 目录(延迟更大,2 分钟一轮)。 - `api.wolfx.jp`(中国大陆地震预警 / 速报)不可达 → 日本与全球链路不受影响;大陆的**两条** 源会同时断(它们共用同一个域名与中继)。这时可以先试设置页的**手动降级开关**(强制走 HTTP 轮询 `/feed?source=cenc_*`);若轮询同样不通,就是该域名在当前网络不可达,不是插件能修的。 - `www.nmc.cn`(中国大陆气象预警:暴雨 / 地质灾害)不可达 → 与上面所有链路都不牵连; 受影响的是这两类预警的播报与历史记录。它走的是普通 HTTPS 轮询,所以**没有可切换的降级通道** (不像 Wolfx 那样有 WS → 轮询的出口),只能等网络恢复。 ### 3.2 当前版本**没有**的降级:不要建议 > 0.5.2 注:本节原先的第一条是「"把 WS 降级成 HTTP 轮询"开关尚未落地」。**它已在 0.5.0 落地** > ——四条自动降级判据 + 设置页的强制开关都是现成能力(见 3.1 与文末入口表)。不要再把它 > 当成"没有的降级"介绍给用户。 - **代理支持**:插件不读 `HTTPS_PROXY`,也不支持配置代理。Node 的原生 `fetch`(undici) **不读**环境变量里的代理设置,所以**不要**建议"设个环境变量就好"。 可靠的做法只有**系统级 / 路由器级透明代理(TUN 模式)**——那超出插件范围,由用户自行决定。 ### 3.3 不可降级:如实告知,不要制造"能修"的错觉 - 上游停更(`stats.stale`)。 - 源改版导致的"数据格式异常"(蓝点)——用户处理不了,等插件更新;设置页有**重试**按钮, 但那只在"源把字段改回来"时有意义。 > 0.5.3 起蓝点的行为有两处变化,排查时要如实告诉用户:① **单条坏数据不再点亮蓝点**——线上 > 是逐条 entry,上游一条脏数据不该让整个源变蓝,现在是"同一失败原因 10 分钟内累计 ≥5 条" > 或"连续 10 条全失败"才升级;② 蓝点**跨刷新存活**(它表达的"等插件更新"与刷新页面无关), > 同时**24 小时没有复现会自动清除**。所以"昨天看到的蓝点今天没了"既可能是插件更新修好了, > 也可能是自愈了——诊断快照里的 `dataHealth` 会写清是哪一种。 - 被限流 / 封 IP。 - 域名在当前网络不可达。 这四类都要明确说:**这不是你能修的**,并给出影响范围。 --- ## 4. 症状:不是"连不上",而是"提醒不响" ### 4.1 先看侧边栏状态点与设置页 - 侧边栏底部一个圆点:**绿** = 全部正常 / **黄** = 连接中、重连中或链路降级 / **中灰** = 数据已过期 / **蓝** = 数据格式异常(等插件更新)/ **红** = 已停止或无法连接 / **灰空心** = 用户关掉了。悬停可看到逐源明细。 - **设置 → 灾害预警 → 源状态**:逐源的连接状态、增量条数、失败次数、增量缺口、最近拉取时间。 把这两处的**原文**复制给 AI,比截图更有用。 ### 4.2 常见的"看起来没坏,其实不响" | 症状 | 先查 | 说明 | |---|---|---| | 有地震但没提醒 | 设置 → 提醒阈值;关注地区 | 震度低于阈值 / 未关注该县,都会只记历史 | | 全球地震没提醒 | 是否配置了「全球关注点」 | **未配置任何关注点时,全球源的消息直接丢弃**(既不入历史也不提醒)。这是有意的,避免每天几十条无关远震刷屏 | | 页面开着但完全没声音 | 设置 → 通知与声音:是否显示"提示音尚未解锁" | 浏览器要求先有一次页面交互才能出声。点一下页面任意位置即可 | | 后台标签页不弹系统通知 | 通知权限 | 需要点"测试系统通知"授权;未授权时回退为页内 toast | | 静默时段内没响 | 静默时段的起止时间 | 静默期间命中的预警仍记历史,只是不响铃;红色等级(EEW / 大海啸 / 震度6弱以上 / L4 以上气象)默认可穿透 | | 气象警报只到 L3 没响 | 这是设计 | 播报边界固定为警戒レベル4 以上;L1〜L3 只记历史(L3 命中会在侧边栏悬停里提示一行) | ### 4.3 用测试按钮区分"链路坏"与"通知坏" 设置页有两个**不发任何网络请求**的本地测试按钮: - **发送测试全球警报(轮换场景)**:构造 EMSC / USGS / NOAA 三种源格式的原文,走真实解析与匹配。 - **发送测试气象警报(轮换场景)**:构造 5 种气象电文。 按钮下方的提示会**如实**写出实际结果(已播报 / 未播报及原因)。据此二选一: - 测试能播报 → 链路与通知都是好的,问题在"没有满足条件的数据"或具体某个源不可达。 - 测试不播报 → 通知 / 阈值 / 关注点配置有问题(提示里写了原因),与外网无关。 --- ## 5. 收尾:给用户的结论模板 AI 完成上述检查后,按这个结构回答: 1. **分类**:属于哪一类(不可达 / 格式异常 / 停更 / 限流 / 本地问题 / 正常无数据)。 2. **证据**:贴出用到的命令与关键输出(`stats` 字段、curl 状态码)。 3. **影响范围**:哪几条链路还能用、哪几条不行。 4. **处置**:能降级的降级(并说明该降级在当前版本是否可用);不能降级的**明确说这不是用户能修的**。 5. **不建议做的事**:不要建议关闭证书校验、不要建议高频重试、不要建议尚未实现的降级开关。 --- ## 附:本文档引用的入口一览 | 入口 | 用途 | 状态 | |---|---|---| | `GET /dsh-quake-alert/feed?source=jma\|usgs\|noaa&since=tail&stats=1` | 读 Host 侧健康计数 | 0.4.1 可用 | | `GET /dsh-quake-alert/feed?source=cenc_eew\|cenc_eqlist&since=tail&stats=1` | 读大陆源的 WS 健康计数(`connected` / `messages` / `reconnects` / `lastError` / `dataTime` / `stale` / `ageSkipped`)。`stale` 由时钟推动,中继真停更时也会变 true | 0.5.0 可用 | | `GET /dsh-quake-alert/stream?source=cenc_eew\|cenc_eqlist` | 大陆源的 SSE 推送(`event: sync` 首帧给出游标、缓冲状态与数据健康;此后每 15 秒一帧 `event: status`,兼作 keep-alive 并承载"中继停更") | 0.5.0 可用 | | `GET /dsh-quake-alert/feed?source=nmc_alarm&since=tail&stats=1` | 读大陆**气象**源(中央气象台 nmc.cn)的健康计数与条目载荷。载荷是 JSON:`alertid` / `title` / `issued` / `kind`(rainstorm / geology)/ `level`(red / orange / yellow / blue)/ `detail`(只有橙 / 红才有正文)。`stats.stale` 由**列表里最新一条的发布时间**推动(超 3 小时),`stats.errors` 增长说明列表请求失败或响应结构变了 | 0.5.2 可用 | | `GET /dsh-quake-alert/areas` | 验证本地回环 webServer 是否活着(返回市区町村表) | 可用 | | 设置页「源状态」区块 | 逐源状态、增量、失败、缺口、最近拉取 | 0.4.1 可用 | | 侧边栏状态点悬停 | 逐源明细(只列异常源) | 0.4.1 可用 | | `node scripts/check-wolfx-live.mjs` | 直接连 Wolfx 复验:建连 / query 指令 / 数据新旧,并按 DESIGN 11.5 的类别给出结论 | 0.5.0 可用,**仅仓库内**(`scripts/` 不入发行包) | | `node scripts/check-cn-e2e.mjs` | Host↔Client 端到端复验:真实 Wolfx → 真实 HTTP SSE → Client 契约 | 0.5.0 可用,**仅仓库内**,需能连上 Wolfx | | `node scripts/check-contracts.mjs` | **契约检查**:拉 8 个源的真实数据过一遍解析器,看上游是否改版(`schema` / `value` → 退出码 1,并打印契约里的 `required` 原文供对照)。网络不可达**不算失败**(只有"上游改版"值得处理)。`--offline` 用 `samples/` 的快照跑,不联网 | 0.5.3 可用,**仅仓库内**(CI 里也跑:手动触发 + PR) | | 设置页「源状态」里的大陆源行 | 显示**当前链路模式**(SSE 推送 / 已降级为轮询 / 已关闭)与收到、失败、降级次数 | 0.5.0 可用 | | Client 侧只读诊断快照 | 设置页「诊断」区块一键生成并复制:聚合状态、逐源状态与数据健康、增量计数、大陆源链路模式、关注点摘要、最近几条记录为什么没响铃 | 0.5.0 可用 | | WS → HTTP 轮询降级开关 | 中间设备重置长连接时的降级路径 | Host 侧**已可用**(`/feed?source=cenc_*`);Client **已自动降级**(EventSource 不可用 / 连续拿不到首帧 / 连上不推流);手动强制开关在设置页「大陆源链路」 | 0.5.0 可用 | | 插件内代理支持 | 需要走代理的网络 | **0.5.x 补齐** | > 文档的可执行性依赖诊断入口。0.4.1 落地了 Host 侧的 `stats=1` 与 UI 上的源状态; > 0.5.0 追加了大陆源的 `stats=1`(含 WS 专属字段)、SSE 的 `sync` / `status` 帧,以及仓库内的 > `scripts/check-wolfx-live.mjs`。Client 侧的只读诊断快照(设置页「诊断」)与手动降级开关 > (`config.cnTransport`)均已落地(见 `DESIGN.md` 11.3 / 11.5)。 > 0.5.2 追加了大陆**气象**源(`source=nmc_alarm`)的 `stats=1`,以及仓库内的 > `scripts/capture-nmc-fixtures.mjs`(重抓真实样本,用于确认"结构是否变了")。 > 0.5.3 追加了 `scripts/check-contracts.mjs`——它是排查"是不是上游改版了"的**第一入口**: > 一次跑完 8 个源的真实数据过解析器,比逐个手敲命令再肉眼对字段快得多。诊断快照里的 > `dataHealth` 也扩成了三层(`data` / `fresh` / `counters`),失败次数与数据时间都在里面。