问题现象
用户在使用 Gateway 服务时,突然遇到以下错误:
gateway connect failed: Error: unauthorized: device token mismatch (rotate/reissue device token)
RPC probe: failed
gateway closed (1008): unauthorized: device token
本文针对 Gateway 设备令牌不匹配(device token mismatch)错误提供排查方案。该问题通常由 CLI 与 Gateway 间令牌不一致引起,常见于服务重启、配置变更或权限问题。解决方案包括重启 Gateway 服务、手动重新签发令牌、排查配置文件冲突及 Systemd 特殊处理。通过监控告警和固定 Token 策略可预防此类问题。核心在于确保 CLI 与 Gateway 持有相同的有效设备令牌。
用户在使用 Gateway 服务时,突然遇到以下错误:
gateway connect failed: Error: unauthorized: device token mismatch (rotate/reissue device token)
RPC probe: failed
gateway closed (1008): unauthorized: device token
关键信息:
Gateway 采用 Token-based 认证机制:
┌─────────────┐ Token A ┌─────────────────┐
│ CLI 工具 │ ◄────────────────► │ Gateway 服务 │
│ (~/.gateway)│ │ (18789 端口) │
└─────────────┘ └─────────────────┘
│ │
│ 设备令牌 (Device Token) │
└──────────────────────────────────┘
设备令牌(Device Token)用于验证 CLI 客户端与 Gateway 之间的身份。当两者持有的令牌不一致时,就会出现 "mismatch" 错误。
| 场景 | 原因 |
|---|---|
| Gateway 重启 | 服务重启后生成新令牌 |
| 配置变更 | 修改配置文件后令牌重新生成 |
| 多用户环境 | 不同用户启动的 Gateway 使用不同令牌 |
| 权限问题 | 令牌文件权限变更导致读取失败 |
| 版本升级 | 新版本可能改变令牌生成逻辑 |
最直接的解决方式是重新生成并同步令牌:
# 1. 停止现有 Gateway
gateway stop
# 2. 确认进程已终止
ps aux | grep gateway
# 3. 清理可能的残留
rm -f ~/.gateway/.gateway-token
# 4. 重新启动
gateway start
# 5. 验证状态
gateway status
如果不想重启服务,可以手动触发令牌轮换:
# 查看当前令牌状态
gateway token status
# 强制重新签发
curl -X POST http://127.0.0.1:18789/api/v1/token/rotate \
-H "Authorization: Bearer $(cat ~/.gateway/.gateway-token)"
# 或者使用 CLI
gateway token rotate --reissue
检查是否存在多个配置文件:
# 查找所有可能的配置文件位置
find ~ -name "gateway.json" 2>/dev/null
# 常见位置:
# ~/.gateway/gateway.json (用户配置)
# ~/.config/gateway/gateway.json (XDG 配置)
# /etc/gateway/gateway.json (系统配置)
# 检查环境变量
env | grep GATEWAY
如果使用 systemd 管理 Gateway,需要注意:
# 检查服务配置
cat ~/.config/systemd/user/gateway.service
# 确认环境变量
systemctl --user show gateway --property=Environment
# 重启服务
systemctl --user restart gateway
# 查看详细日志
journalctl --user -u gateway -f
# 默认位置
~/.gateway/.gateway-token
# 内容示例(JWT 格式)
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
CLI 发起连接 │ ▼ ┌──────────────────┐ │ 1. 读取本地 Token │ │ (~/.gateway/...)│ └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ 2. WebSocket 握手 │ │ 携带 Token │ └────────┬─────────┘ │ ▼ ┌──────────────────┐ │ 3. Gateway 验证 │ │ 对比内存中的 Token│ └────────┬─────────┘ │ ┌────┴────┐ ▼ ▼ 匹配 不匹配 │ │ ▼ ▼ 连接成功 返回 1008 要求重新签发
根据代码分析,以下操作可能触发 Token 变更:
# ~/.config/systemd/user/gateway.service
[Service]
Type=simple
ExecStart=/usr/bin/node /home/ubuntu/.npm-global/lib/node_modules/gateway/dist/index.js gateway --port 18789
Restart=on-failure
RestartSec=5
# 确保只有一个实例
ExecStartPre=/bin/sh -c 'pgrep -f "gateway" && exit 1 || exit 0'
// ~/.gateway/gateway.json
{
"gateway": {
"port": 18789,
"auth": {
"mode": "static",
"token": "dev-token-for-local-only"
}
}
}
⚠️ 警告:仅用于本地开发,生产环境请使用动态 Token!
#!/bin/bash
# ~/bin/gateway-health-check.sh
if ! gateway status | grep -q "running"; then
echo "$(date): Gateway 异常,尝试重启..." >> ~/.gateway/health.log
gateway restart
fi
# 添加到 crontab(每 5 分钟检查)
*/5 * * * * /home/ubuntu/bin/gateway-health-check.sh
# 设置日志级别
export GATEWAY_LOG_LEVEL=debug
# 重新启动并查看日志
gateway stop
gateway start 2>&1 | tee /tmp/gateway-debug.log
# 解码 JWT(需要 jq)
cat ~/.gateway/.gateway-token | cut -d'.' -f2 | base64 -d 2>/dev/null | jq .
# 示例输出:
# {
# "sub": "gateway-cli",
# "iat": 1708195200,
# "exp": 1708789999,
# "jti": "unique-device-id"
# }
| 错误场景 | 快速解决 |
|---|---|
| 突然出现 mismatch | gateway restart |
| 使用 systemd | systemctl --user restart gateway |
| 多用户环境 | 确保使用同一用户运行 CLI 和 Gateway |
| 频繁出现 | 检查是否有其他进程在重启 Gateway |
核心要点:

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online
将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online