Files
wecom_it_smart_desk/docs/09-部署运维/00-标准故障排查手册.md
T
Simon bea288e414 feat: 2026-07-11 全量更新 - 代办集成+会议室预定+知识迭代修复+UI统一+Bug修复
== 已部署上线 (9项) ==
- 代办事项真实数据源集成 (企微审批API 8bug修复链)
- H5/坐席端 Logo样式统一+绿色背景
- 视频引导页修复 (localStorage key v2)
- 坐席端 v9 Vue版本修复 (ElMessage._context)
- 截图按钮 v10 修复 (getDisplayMedia user gesture)
- 扫码样式恢复+H5扫码登录跳转修复
- H5截图快捷键提示

== 代码完成待部署 (3项) ==
- 知识迭代3Bug修复 (#8 POST端点/#7 MERGE幂等/#6 过期检查)
- 会议室预定-小鱼易联终端 (40文件, 40/40测试通过)
- IT资产升级审批推送 (asset_service.py)

== 需求文档 (2项) ==
- 坐席端AI辅助消息框-PRD (4项新功能确认)
- 坐席端布局优化建议 v2.0 (7天计划)

== 新增文档 ==
- 日报-2026-07-11.md
- 知识迭代Bug修复报告-20260711.md
- 会议室预定-部署指南.md
- CHANGELOG.md 更新

== 测试 ==
- test_todo_integration.py: 40/40
- test_meetingroom.py: 40/40
- test_bugfix_ki_suggestions.py: 21/21
2026-07-11 23:13:10 +08:00

27 KiB
Raw Blame History

00 · 标准故障排查手册

版本: v1.4 | 日期: 2026-07-10 | 维护人: 宋献 / 助理 定位: 所有故障排查前首先查看本手册最新: 方案 C(卷挂载)已上线,§1.4 更新为 volume 挂载验证 + CASE-20260710-02 标注根因已消除 + 错误码速查更新

| v1.4 | 2026-07-10 | 方案 C 上线:§1.4 改为 volume 挂载验证 + 错误码速查更新 + CASE-20260710-02 根因已消除标注 |

前置阅读: 运维手册(部署/回滚/备份/应急) · SOP-04 应急响应


0 文档说明与版本

0.1 为什么要有这本手册

原先"故障排查"主题散落在 9 份文档中(500 诊断、服务器端诊断、故障排查指南、4 份修复记录、通讯链路、deploy/02 手册、调试验证指南),内容重复且存在断链。任何故障都应先翻这一本,按决策树定位,再查案例库。

0.2 验证完成硬规则(最重要)

宣布"已修复 / 已完成"之前,必须提供真实可验证证据,不得仅凭 curl / 日志 / "我认为"

  • 前端 / 登录类问题:真实浏览器登录或操作截图(用真实 Chromium / Playwright 打开页面、输入凭据、完成动作、进入目标页的截图)。
  • API / 后端类问题:端到端调用证据(curl 真实返回 + 必要时代码层拦截响应体)。
  • 禁止:只因 docker logs 无报错就断言修复;只因"我认为应该好了"就宣布完成。

0.3 版本历史

版本 日期 变更
v1.0 2026-07-07 整合 9 份散落文档 + 新增 CASE-20260707-01Redis urlparse 挂起)
v1.1 2026-07-08 新增 CASE-20260708-01~06 + nginx 急救流程 + 端到端验证更新
v1.2 2026-07-10 新增 CASE-20260710-01CSP 拦截内联 JS+ Step 0 响应头检查 + sed -i inode 教训
v1.4 2026-07-10 方案 C 上线:§1.4 改为 volume 挂载验证 + 错误码速查更新 + CASE-20260710-02 根因已消除标注
v1.3 2026-07-10 新增 CASE-20260710-02(镜像缺文件导致 API 404)+ 判定矩阵扩展 + 部署前同步检查清单

1 快速诊断决策树

1.1 三步隔离法(通用)

任何"页面打不开 / 网络连接失败 / 接口无响应 / 422"都先用三步隔离,定位是 nginx、后端、还是依赖(DB / Redis)的问题。

Step 0HTTP 响应头检查(页面 200 但功能异常时首先执行)

# 检查响应头,特别关注 Content-Security-Policy / X-Frame-Options / X-Content-Type-Options
curl -ksI https://itsupport.servyou.com.cn/h5/ | grep -iE 'content-security|x-frame|content-type'

为什么要有 Step 0:页面返回 HTTP 200、HTML 正常加载,但 JavaScript 不执行——这类问题无法被三步隔离法捕获。根因通常是 CSPContent-Security-Policy)头限制了 script-src,导致内联 <script> 被浏览器静默拦截。详见 CASE-20260710-01。

# 第1步:nginx 层可达性(在服务器执行;浏览器走 HTTPS,故用 https 而非 localhost
curl -ksI https://itsupport.servyou.com.cn/itadmin/ | head -5
curl -ksI https://itsupport.servyou.com.cn/api/health   | head -5

# 第2步:直连后端(绕过 nginx,确认后端本身)
docker compose exec backend curl -s http://localhost:8000/health
# 或容器外:
docker exec wecom_it_backend curl localhost:8000/health

# 第3步:依赖可达性
docker compose exec redis redis-cli ping          # 期望 PONG
docker compose exec postgres pg_isready -U wecom   # 期望 accepting

判定矩阵

现象 第1步 第2步 第3步 定位
浏览器"网络连接失败"、curl 永远不返回 200 200 挂起 依赖挂起(如 Redis 连到错误 host
全站 500 500 / 后端异常,看 backend 日志
某端点 502 502 后端 down 后端未起 / 缺 PYTHONPATH=/app
/itdesk/ 200 但 /api/... 404 nginx 代理路径不匹配
422 API 校验失败 请求体缺字段(见 §2
页面 200 但 JS 不执行 200 CSP 拦截内联 JS(检查 Content-Security-Policy 头的 script-src 是否含 'unsafe-inline',见 Step 0 / CASE-20260710-01
API 404 但本地代码存在 200 404 镜像缺文件(方案 C 前根因)。卷挂载模式下检查 volume 挂载 + ./app/ 代码完整性(见 CASE-20260710-02 / §1.4

1.2 关键陷阱:URL 特殊字符导致依赖"静默挂起"

详见案例 CASE-20260707-01。密码含 @ # 时,urlparse 把它们当 URL 分隔符,连到不存在的 host,连接无限挂起(浏览器表现为"网络连接失败",curl 永远等不到返回)。这是最隐蔽的一类故障——容器全 Up、nginx 全 200、唯独业务接口卡死。

1.3 在服务器跑诊断的 3 种方式(经堡垒机)

公司服务器只能经堡垒机(sxn@10.212.189.210:2222ssh sxn@10.90.5.110)操作,无法本地 scp。推荐用 jumpserver-ops 工具自动执行:

# 本地(Windows)用 jumpserver-ops 跑(自动复用会话,~2-3s/条):
python jms_ops.py exec -c "docker compose ps" -c "curl -ksI https://itsupport.servyou.com.cn/api/health" --reuse

原"服务器端跑诊断"的 3 种手工方式(PuTTY 跳堡垒机 / scp 上传 / 服务器下载)已不推荐,统一用上述 jumpserver-ops 自动化。

1.4 部署前检查清单(卷挂载模式 — 方案 C)

触发条件:任何涉及后端代码变更的部署(新增/修改 .py 文件、新增 Python 依赖)。

硬规则:后端代码部署方式(方案 C 卷挂载,2026-07-10 上线)

变更类型 正确命令 禁止操作 耗时
.py 文件变更 cd /opt/wecom-it-desk && docker compose restart backend docker compose build ~15-30 秒
requirements.txt 变更 docker compose build backend && docker compose up -d backend ~60-90 秒
.env / docker-compose.yml 变更 docker compose up -d backend ~10 秒

代码通过 ./app:/app/app volume 挂载到容器,不烘焙进镜像。改代码只需 restart 让 uvicorn 重新加载,无需重建镜像。docker compose build 只在 Python 依赖变化时才需要。

背景:方案 C(卷挂载)已于 2026-07-10 上线。代码不再烘焙进 Docker 镜像,而是通过 ./app:/app/app volume 挂载到容器。backend/app/ 旧代码目录已删除。部署前只需验证 ./app/ 代码目录完整性和 volume 挂载状态。

⚠️ 历史背景(已消除):方案 C 前,服务器存在两份代码目录 app/backend/app/,不同步导致镜像缺文件(见 CASE-20260710-02)。方案 C 消除了此根因。

检查清单(经堡垒机执行)

# 1. 验证 ./app/ 关键文件存在
for f in app/__init__.py app/main.py app/api/auth.py; do
  [ -f "/opt/wecom-it-desk/$f" ] && echo "PASS: $f" || echo "FAIL: $f missing"
done

# 2. 验证 volume 挂载正常(容器内可访问代码)
docker exec wecom_it_backend ls /app/app/main.py

# 3. 验证代码一致性(宿主机与容器内 MD5 一致)
HOST=$(md5sum /opt/wecom-it-desk/app/main.py | awk '{print $1}')
CONTAINER=$(docker exec wecom_it_backend md5sum /app/app/main.py | awk '{print $1}')
[ "$HOST" = "$CONTAINER" ] && echo "PASS: code match" || echo "FAIL: code mismatch"

# 4. 如有新依赖,检查 requirements.txt
# diff 本地 requirements.txt 与服务器上的(如需要)

# 5. 代码更新后只需重启(无需重建镜像)
cd /opt/wecom-it-desk && docker compose restart backend

简化版(用 jumpserver-ops 一键检查)

python jms_ops.py exec \
  -c "for f in app/__init__.py app/main.py app/api/auth.py; do [ -f /opt/wecom-it-desk/\$f ] && echo \"PASS: \$f\" || echo \"FAIL: \$f\"; done" \
  -c "docker exec wecom_it_backend ls /app/app/main.py && echo PASS_mount" \
  --reuse

⚠️ 代码更新后 docker compose restart 即可(15-30 秒)。仅当 requirements.txt 有变化时才需要 docker compose build


2 常见错误码速查(E5xx

错误码 含义 首选排查
E500 后端未捕获异常 / 缺列 / 缺依赖 docker compose logs backend --tail=200 | grep -i error;查数据库缺列 / 缺 Python 依赖
E502 nginx 连不到后端 后端容器 unhealthydocker logs wecom_it_backend;是否缺 PYTHONPATH=/app
E503 服务过载 / 维护 docker statsdocker inspect ... Health
E403 IP 白名单 / 无权限 grep allow /opt/wecom-it-desk/nginx/nginx.confadmin 角色不足
E422 请求体校验失败(Pydantic 确认必填字段齐全(如登录需 user_id+name
网络失败 / 连接挂起 依赖不可达(最常见 Redis 配置错) 见 §1.2 / CASE-20260707-01
页面 200 但 JS 不执行 CSP 头 script-src'unsafe-inline',内联 <script> 被浏览器静默拦截 curl -ksI <URL> | grep content-security;检查 script-src 是否含 'unsafe-inline'(见 CASE-20260710-01
API 404 但本地代码存在 镜像缺文件(方案 C 前根因已消除)。卷挂载模式下检查:volume 是否正常挂载 + ./app/ 是否有该文件 docker exec <容器> ls /app/app/api/auth.pydocker exec <容器> md5sum /app/app/main.py 对比宿主机(见 §1.4 / CASE-20260710-02

2.1 E500 常见根因速查

  • 数据库缺列 → ALTER TABLE ... ADD COLUMN IF NOT EXISTS ...
  • 缺 Python 依赖 → requirements.txt 补依赖后重构建(如 wordfilter
  • 代码签名不匹配(如缺 current_agent 参数)→ 修函数签名
  • import aioredis 与 Python 3.12 冲突 → 改 redis.asyncio,设 PYTHONPATH=/app

2.2 E422 登录场景

登录端点 /api/agents/login 要求 user_id(必填) + name(必填);缺字段直接 422。前端 admin.tsname: inputUserId 发送。


3 诊断脚本与命令

3.1 一键系统状态

#!/bin/bash
echo "==== 容器状态 ===="; docker compose ps
echo "==== 端口 ====";      netstat -tlnp | grep -E "80|443|5432|6379|8000"
echo "==== 前端文件 ====";  ls -la /opt/wecom-it-desk/html/itdesk/ 2>/dev/null | head
echo "==== backend 错误 ===="; docker compose logs --tail=20 backend 2>&1 | grep -i error
echo "==== Redis ====";     docker compose exec redis redis-cli ping
echo "==== PG ====";        docker compose exec postgres pg_isready -U wecom

3.2 500 错误快速对照

现象 诊断
ls .../frontend-h5/dist/ No such file 部署包未含 dist
nginx 容器内 ls /usr/share/nginx/html/itdesk/ 失败 挂载路径错
curl /itdesk/ 返回 500 后端代理或 SPA 内部错
/itportal/ 200 但 /itdesk/ 500 H5 端特定问题
nginx 日志有 proxy_pass 后端未起 / 端口不通
nginx 日志 rewrite ... cycle try_files 死循环,修 nginx 配置

3.3 通讯链路检查点(用户 ↔ 坐席 ↔ 企微)

  • 用户→系统:企微回调 /wecom/callbackmessage_router → 消息入库 → 坐席 WS / 轮询
  • 系统→用户:坐席 POST /conversations/{id}/messageswecom_service.send_text_message()errcode=0)→ 用户收到
  • 已知风险:非文本消息(图片/文件)不推送;dev_mode 跳过企微推送;企微 API 失败静默(仅日志)
  • 检查点文件:wecom_callback.py / message_router.py / messages.py / wecom_service.py / ws_manager.py

3.4 WebSocket 失败

grep -r 'websocket' /opt/wecom-it-desk/nginx/nginx.conf   # 需 proxy_http_version 1.1 + Upgrade/Connection
docker logs wecom_it_backend | grep -i websocket

4 案例库(倒序,编号 CASE-YYYYMMDD-序号)

CASE-20260710-02 · 坐席端/管理端登录"获取二维码失败"(Docker 镜像缺文件)

  • 现象:坐席端和管理端登录均报"获取二维码失败",浏览器控制台显示 WebSocket connection failed + /api/auth/qrcode 返回 404。
  • 误判历程
    1. 误判为 Nginx 未 reload → nginx -s reload/auth_qrcode/create 返回 200,但前端实际调用的是 /auth/qrcode(不同路由)
    2. 尝试 docker cp 临时复制 auth.py 到容器 → 重启后文件丢失(临时文件系统)
    3. 发现连锁依赖:auth.py 依赖 schemas/auth.pyservices/auth_service.pymodels/login_log.py,全部缺失
    4. 真正根因:服务器存在两份代码——/opt/wecom-it-desk/app/(较新,开发用)和 /opt/wecom-it-desk/backend/app/(较旧,Docker 构建用)。新增的 auth.py 只放到了 app/,未同步到 backend/app/,导致镜像构建时打包的是旧代码。
  • 根因:服务器上 app/(开发目录)与 backend/app/Docker 构建目录)不同步,docker compose build 打包了旧代码。同时 requirements.txt 也未同步(新增 neo4j 依赖),首次重建后容器因缺包 crash。
  • 修复
    1. 用 Python 脚本同步 /opt/wecom-it-desk/app//opt/wecom-it-desk/backend/app/
    2. 上传最新 requirements.txt(含 neo4j>=5.26.0)到 /opt/wecom-it-desk/backend/
    3. docker compose build backend(约 65s
    4. docker compose up -d backend
    5. 验证:后端日志显示 GET /auth/qrcode → 200 OK,容器状态 healthy
  • ⚠️ 教训
    1. 部署新功能时必须检查两份代码一致性app/backend/app/ 不同步 = 镜像缺文件。
    2. docker cp 是临时方案:容器重启后丢失。永久修复必须重建镜像。
    3. 全链路检查:代码同步 → requirements 更新 → 镜像重建 → 容器重启,四步缺一不可。
  • 防护措施:见 §1.4 部署前检查清单。
  • 根因已消除2026-07-10):方案 C(卷挂载)已上线。代码不再烘焙进 Docker 镜像,通过 ./app:/app/app volume 挂载到容器。backend/app/ 旧代码目录已删除,不再存在"两份代码不同步"问题。此案例保留作为历史参考。

CASE-20260710-01 · 扫码登录成功页 JS 不执行(CSP 拦截内联脚本)

  • 现象:企微扫码登录成功后,"登录成功"页面显示但不会自动关闭。页面停在"JS加载中…",所有内联 <script> 从未执行。后端返回 HTTP 200,HTML 内容正确。
  • 误判历程5 轮,供反思):
    1. 误判为未引入企微 JS-SDK → 添加后仍不工作
    2. 误判为 JSAPI 签名 URL 协议不一致(HTTP vs HTTPS)→ 修复 X-Forwarded-Proto 后仍不工作
    3. 误判为外部 JS-SDK 加载失败 → 移除外部依赖改用 WeixinJSBridge 仍不工作
    4. 误判为 WeixinJSBridgeReady 事件未触发 → 改为轮询检测仍不工作
    5. 真正根因Nginx CSP 头 script-src 'self' 'unsafe-eval' https://res.wx.qq.com 缺少 'unsafe-inline',所有内联 <script> 被浏览器静默拦截。JS 从未执行过——前面 4 轮的代码修改全部白费。
  • 根因Content-Security-Policyscript-src 指令未包含 'unsafe-inline',浏览器根据 CSP 规范静默拦截所有内联脚本(<script>...</script>onclick= 等内联事件处理器)。页面 HTML 正常返回,但 JS 引擎从未解析执行任何脚本。
  • 修复Nginx 配置 CSP 头 script-src 加入 'unsafe-inline'
    add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://res.wx.qq.com; ..." always;
    
    修改后 docker restart wecom_it_nginx(不能用 reload,见下方教训)。
  • 验证:用户手机企微扫码 → 显示"登录成功"→ 1 秒后自动关闭返回企微
  • ⚠️ 教训
    1. 页面 200 + HTML 正确 ≠ JS 会执行。排查前端功能异常时,Step 0 应检查 HTTP 响应头(CSP / X-Frame-Options),而非直接深入代码逻辑。
    2. CSP 拦截是静默的——浏览器控制台报错但页面无任何错误提示,后端日志也完全正常。如果不主动检查响应头,会一直在代码层面打转。
    3. 5 轮误判的共同盲点:每次都在"JS 代码为什么不对"上做文章,从未怀疑"JS 根本没执行"。正确的排查路径应该是先在浏览器 F12 控制台输入 1+1 确认 JS 引擎可用,再看 Console 是否有 CSP 报错。

CASE-20260707-01 · 管理后台登录"网络连接失败"(Redis 密码 URL 解析挂起)

  • 现象:浏览器登录 /itadmin/ 一直转圈 / "网络连接失败"API 永远不返回;curl 超时。
  • 根因REDIS_URL=redis://:R3d!s@2026#Secure@redis:6379/0,密码含 @#urlparse()# 当 fragment、@ 当 host 分隔符 → 解析出 host=2026、password=R3d!s → 连到不存在的 host → 无限挂起。后端 token_service.create_token()redis.setex 时卡死。
  • 修复
    1. docker-compose.yml 后端 REDIS_URL 改为 URL-encodedredis://:R3d%21s%402026%23Secure@redis:6379/0
    2. backend/app/config.pycreate_redis_client 增加 unquote() 解码 + socket_connect_timeout=5 / socket_timeout=5
    3. redis 服务 --requirepass 与 healthcheck 保持明文 R3d!s@2026#Secure(与后端解码后的明文一致)
    4. 重建 backend + redis 容器
  • 验证Redis PING→PONGcurl 登录 /api/agents/login 返回 HTTP 200, 0.64s, role:admin真实浏览器登录截图进入 dashboard 成功(见 §5)。
  • ⚠️ 同类复发防护:本项目 Redis 密码含特殊字符,改 docker-compose 密码时两处必须一致(后端 REDIS_URL 用 encodedredis --requirepass 用明文);且 config.py 必须 unquote

CASE-20260705-01 · 502 Bad Gateway(后端启动失败 / aioredis + PYTHONPATH

  • 现象:坐席端登录失败 502,后端容器 unhealthy
  • 根因:旧镜像 import aioredis 与 Python 3.12 冲突(TypeError: duplicate base class TimeoutError);且未设 PYTHONPATH=/appModuleNotFoundError: No module named 'app.core'
  • 修复Dockerfile 改 import redis.asyncio as aioredisdocker-compose.ymlPYTHONPATH=/app;重建后端。

CASE-20260705-02 · 坐席端 4 个问题(消息列表 500 / 页面抖动 / 发送失败 / 文档缺失)

  • #1 消息列表 500list_messages()current_agent: Agent = Depends(get_current_agent) 参数。修 messages.py + 重启。
  • #2 页面短暂不可用:容器重启波动,自愈。
  • #3 发送失败 ModuleNotFoundError: wordfilterrequirements.txtwordfilter==0.2.7,容器内 pip install 临时修 + 同步 requirements。
  • #4 文档补"Python 依赖管理"章节(服务器部署手册)。

CASE-20260613-01 · H5 消息 500(缺列 + AIHandler 签名)

  • 现象POST /api/h5/.../messages 500column conversations.impact_scope does not exist + AIHandler.__init__() missing 'ai_service'
  • 根因DB 缺 4 列(impact_scope/is_blocking/emotion_state/dify_conversation_id);dependencies.py 两处 AIHandler() 未传 ai_service
  • 修复ALTER TABLE 补列;dependencies.pyAIHandler(ai_service=AIService())

附:企微工作台"加载失败 / 无限加载"2026-07-04

  • 根因1nginx 未正确挂载 nginx.conf → API 404,重建 nginx 容器。
  • 根因2:后端 h5.py 存在 NameError: _require_wework_ua → 代码未同步最新,复制最新 h5.py + 重启。

CASE-20260708-01 · 后端路由 404 — OTP 统一路由未注册

  • 现象POST /api/auth/otp-bind 返回 404;前端 OTP 绑定面板密钥和二维码不显示。
  • 根因:部署 otp.py 时漏部署 router.pyapi_router.include_router(otp_router) 未执行。本地 router.py 包含服务器不存在的模块(knowledge_iteration / approval_queue / vision / ragflow_ingestion / automation),导入失败导致整个 router.py 加载失败。
  • 修复:上传 router.py,注释掉服务器上不存在的模块导入;同时修复 otp.py@require_role("admin") 装饰器与显式 current_user 参数的冲突(服务器旧版 require_role 会自动追加 current_user)。
  • 教训:修改路由时务必同步部署 router.py,否则新端点虽然代码存在但永远不会注册。

CASE-20260708-02 · 管理端 API 全部 404 — nginx 正则 location proxy_pass 缺 rewrite

  • 现象/api/admin/roles/api/admin/dashboard/overview 等全部返回 404。
  • 根因nginx 配置中 location ~ ^/api/admin/(正则匹配)内 proxy_pass http://backend_api; 不带尾部斜杠,导致 /api/ 前缀未剥离,后端收到 /api/admin/roles 而非 /admin/roles。带尾部斜杠又会报错 "proxy_pass" cannot have URI part in location given by regular expression
  • 修复:去掉嵌套正则 location,改为统一 location /api/proxy_pass http://backend_api/;(尾部斜杠剥离 /api/ 前缀)。
  • 教训nginx 中正则 location 不能直接用 proxy_pass 带 URI;需要时用 rewrite 剥离前缀。

CASE-20260708-03 · sxn 扫码登录无 admin 权限 — QR 扫描写死 roles=["agent"]

  • 现象:管理后台扫码登录后,OTP 管理/角色管理返回 403/无权限提示。sxn 账密登录正常。
  • 根因auth_qrcode.py 扫码自动确认逻辑中,create_token 写死了 roles=["agent"],未调用 get_user_roles()
  • 修复:扫码确认改为调用 RoleMappingService.get_user_roles() 获取真实角色。
  • 教训:所有登录路径(账密/扫码/OAuth)的角色获取必须统一走 get_user_roles()

CASE-20260708-04 · 用户角色列表为空 — get_user_roles() 只查 user_roles

  • 现象:管理后台角色管理页"用户角色分配"表格为空;OTP 管理 API 403。
  • 根因get_user_roles() 仅查询 user_roles 表,但旧数据(包括 sxn 的 admin)只存在于 agents.role 字段。user_roles 表为空时返回 ["user"]
  • 修复get_user_roles() 增加 agents.role 回退查询;新增 GET /admin/roles/user-roles 端点;前端 Roles.vue 加载用户角色分配数据。
  • 教训:新旧数据迁移时需确保角色数据完整同步到 user_roles 表。

CASE-20260708-05 · 企微工作台点"IT支持服务"进坐席登录页 — 员工端口缺失

  • 现象:企微工作台 → IT支持服务 → 显示坐席扫码登录页,而非员工 H5 页面。
  • 根因(1) nginx /itdesk/ 被错误配置为 301 重定向到 /itagent/(2) H5 构建文件未挂载到容器(docker-compose.yml 缺少 ./html/h5 挂载);(3) 改重定向到 /h5/ 后仍失败,因为 H5 vite base/itdesk/OAuth 回调依赖此路径。
  • 修复/itdesk/ 直接 alias 到 H5 构建目录(/usr/share/nginx/html/h5/),不再 301 跳转;docker-compose.yml 添加 h5 volume 挂载;根路径 / 改为 302 → /h5/
  • nginx 关键配置alias + try_files SPA 模式):
    location /itdesk/ {
        alias /usr/share/nginx/html/h5/;
        index index.html;
        try_files $uri $uri/ /index.html;
    }
    
    注意:fallback 用 /index.html 而非 /itdesk/index.html——alias 会自动映射。
  • 教训:前端 vite base 路径必须与 nginx 服务路径一致;OAuth 回调路径不能用 301 重定向。

CASE-20260708-06 · 管理端 OTP 用户列表返回错误结构

  • 现象OTP 管理页面提示加载失败,/auth/otp-admin-users 返回 403。
  • 根因(1) admin_list_otp_users 返回普通数组,前端期望 {total, items} 结构;(2) @require_role("admin") 因 token 不含 admin 角色返回 403(见 CASE-03/04)。
  • 修复:后端改为分页查询返回 {total, items};增加 keyword/bound/page/page_size 参数支持。

附:nginx 配错急救流程(2026-07-08 实战总结)

步骤 操作
1 备份:sudo cp /opt/wecom-it-desk/nginx/nginx.conf /tmp/nginx.bak
2 修改宿主文件后必须 docker stop nginx && docker start nginxreload 有时不生效)
3 验证容器内配置已同步:docker exec wecom_it_nginx grep 关键字 /etc/nginx/nginx.conf
4 确认语法:docker exec wecom_it_nginx nginx -t
5 检查容器状态:docker ps --filter name=wecom_it_nginx
6 agent-browser 打开 URL 做端到端验证
7 避免用 sed 修改 nginx 配置——$uri/$host 等变量会被 shell 解释;用 Python 脚本或直接上传文件
8 ⚠️ sed -i 会创建新 inodeDocker bind mount 不跟踪新 inode,导致容器内看到的仍是旧文件。用 sed -i 修改后必须 docker restart(而非 nginx -s reload),或改用 sed 不带 -i + 重定向写入原文件(保持 inode 不变)

5 端到端验证完成标准(原《调试验证指南》整合)

宣布完成前,按 §0.2 提供真实证据。

5.1 管理后台验证(最常见)

步骤 操作 预期
1 浏览器开 https://itsupport.servyou.com.cn/itadmin/ 登录页
2 输入 sxn / test123 登录 进入 dashboard,右上角显示"宋"
3 仪表盘数据渲染 在线坐席 / 今日会话 / 平均响应 / AI 命中率 有值
4 API 拦截 POST /api/agents/login HTTP 200 + role:admin + token

5.2 通用验证清单(P0 必须通过)

  • H5 登录流程正常(企微 OAuth 跳转 → 回跳 → 欢迎)
  • 坐席登录正常,可接单
  • 消息收发双向正常(文本 / 图片 / 文件)
  • 邀请功能闭环
  • 管理后台可访问且数据正常

5.3 真实浏览器证据获取(推荐 Playwright)

本机 Windows 可直接访问服务器(TCP 443 通)。用 playwright-core 驱动已安装的 Chromium(路径 ~/.agent-browser/browsers/chrome-*/chrome.exe),拦截 API 响应作为证据,避免 CLI 工具 IPC 不稳。


6 升级与应急(交叉引用,不重复)


7 参考文档索引

文档 说明
01-项目总览/01-智能IT服务系统运维手册-20260704.md 部署 / 回滚 / 备份 / 应急(故障排查章已并入本手册)
10-项目管理/SOPs-标准流程/SOP-04-应急响应.md 应急响应 SOP
09-部署运维/deploy/01-部署指南.md 部署操作
09-部署运维/deploy/03-版本记录.md 版本与修复记录索引
09-部署运维/deploy/服务器部署手册.md 服务器部署细节
06-测试质量/testing-测试/E2E-CHECKLIST-v0.7.0.md E2E 验收清单

维护说明: 本手册为故障排查唯一入口。新增案例请按 CASE-YYYYMMDD-序号 倒序追加到 §4;改动需同步本文件版本号与日期。