一次 Anki 登录不上的找 bug 经历
本文记录我的一次找 bug 经历。
之前,因为服务器被刷流量,导致宕机。所以我需要写一些防爆破规则。
在整理各类规则时,我没管 Anki。有空再用 Anki 时,Anki 死活无法登录了。
报错不一定可靠
报错越大越含混,越不可靠。报错越细节,越可靠。
账密有错
表面上,报错:Email or password was incorrect. please try again.
这就有以下几个怀疑方向。
| 怀疑 | 证据 | 结果 |
|---|---|---|
| 我的 AnkiWeb 账密有误 | 但我明明在 AnkiWeb 上真实地登录着,它不可能有误 | 排除 |
| Anki 不支持自定义账密,必须使用 AnkiWeb 账密 | 但很多网贴都清楚地记载着,AnkiWeb 账密和自定义账密,两者完全分开,可以不同。Anki 很支持自定义账密 | 排除 |
| 我出现了 typo 错误 | 但以我的细心程度,以及多番检查,以及不使用 copy and paste,没有误字漏字 | 排除 |
请求地址有错
表面上,报错:
- Connection timed out. Please try again. If you see frequent timeouts, please try a different network connection.
- Error details: error sending request for url ()
ChatGPT 和论坛许多人都认为是请求地址不对,认为是代理或恶意软件拦截了请求。殊不知这报错太宽泛,最终的实用价值很低。
Issue 和论坛不一定可靠
| 怀疑 | 证据 | 结论 |
|---|---|---|
| 发版出了问题 | 但本 Anki 版本已经发出来七个月了,要有问题早就引发热烈讨论了,GitHub Issue 里没人提 | 我没有理性排除发版问题,还怀疑别人都用的老版。有点傻乎乎,以后软件问题还是不要首先怀疑原作者的发版有问题 |
| 遭遇了恶意封禁 | 论坛里许多人提到因恶意软件导致无法登录。十几个相同案例让我非常怀疑自己遇到了相同情况 | 无法排除,耗费了大量时间查找线索 |
控制台不一定可靠
| 控制台 | 证据 | 结论 |
|---|---|---|
| 服务端控制台 | 错误显示得少。正确时显示得多 | 用处不大 |
| 客户端控制台 | Windows Anki 可以用 anki_conselo.bat 运行。Linux Debian Anki 可以在 Terminal 里运行。同样是错误显示得少。正确时显示得多 | 用处不大 |
| Ctrl Shift ; | 调试窗口在插件开发过程中,应该比较有用 | 对此次排错用处不大 |
版本问题应该最早排查
Anki 有不同平台,所以我换了 Windows 端、Android 端、Linux Debian 端,皆报错一致,无法登录。此时第一时间应该怀疑不是客户端问题,而是服务端问题。但我没这种直觉,还是按部就班,怀疑是新版问题,于是接着用了三四个旧版,均报同样的错误。
抓包比较有效
抓包有两种思路:流量出站没?流量入站没?
out
最有效的命令,非在服务器之外运行curl -vk 1.2.3.4:12345莫属,它可以初步判定,有没有流量出去,对方有没有反应,哪怕是拒绝。
netstat -ano | findstr :443 在 Windows 里能很方便判断,有没有流量出去。
在 Windows 里,按住梅花键,再输入“资源监视器”,在“资源监视器”里勾选想监视的程序,也能看见它有没有使用磁盘、网络、内存,用处不大,但有点。优点是最简单方便。
in
tcpdump -i any port 29595 这条命令可以监测,任何尝试访问 29595 端口的流量。
who
除了出站、进站流量,有时还要关注下我主动开启的进程。
# 查看
ps aux | grep anki
# 关闭
kill pid
查日志才是最实用手段
日志,是服务器上的宝藏。看懂日志,就能解决一切问题。关于日志的详解,请见:Apache 日志详解。
开启日志
LogLevel warn proxy:trace3 proxy_http:trace3
ErrorLog ${APACHE_LOG_DIR}/error.log
自造日志
SetEnvIfNoCase User-Agent "^$" ua_empty
LogFormat "%h %l %u %t \"%r\" %>s %b ua=\"%{User-Agent}i\" empty=%{ua_empty}e" anki_debug
CustomLog /var/log/apache2/anki_debug.log anki_debug
过滤日志
tail 的 -f 选项,简直是查报错的神器,客户端点击一次,服务端的日志就出现一次。有没有连上,连上是什么反应,一清二楚。在 error.log 里过滤 ip,也相当有用。
tail -f /var/log/apache2/access.log | grep 1.2.3.4
cat /var/log/apache2/error.log | grep 1.2.3.4 | tail -n 100
通过第二行命令,成功抓到以下日志:
[proxy:trace1] mod_proxy.c(969): [client 1.2.3.4:42691] AH03464: URI path '/hi/sync/hostKey' matches proxy handler 'proxy:...
[authz_core:error] [client 1.2.3.4:42691] AH01630: client denied by server configuration: proxy:...
[proxy:trace2] mod_proxy.c(848): [client 1.2.3.4:42691] AH03461: attempting to match URI path '...' against prefix '/.../' for proxying
看到 denied 基本可以确定是服务器的 apache 配置在背后拒绝了。
最小化测试是最佳手段
改了 apache 配置,记得要systemctl restart apache2重启。
如果只有一行配置可能有毛病,那可以考虑把别的配置都注释掉,去掉所有别的配置的影响,只留怀疑的那一行。如果只留它,还出了毛病,那肯定就是它的毛病。如果只留它,没出毛病,那证明不是它的毛病。
最后,通过过滤日志、自造日志、最小化测试,成功查出原因:我在服务器里设置了拒绝无头 UA 访问。重新开启,就解决了问题。