现象
最近用自己搭的代理访问 Google Gemini 和 AI Studio 的时候,页面总是花的------侧边栏的文字缺胳膊少腿,图标全变成了方块或者乱码字符,有时候甚至整个页面只剩个白板。

打开 F12 一看,控制台有红色的 ERR_CONNECTION_CLOSED,失败的请求清一色指向 www.gstatic.com 和 fonts.gstatic.com。

而且换个节点就好了,说明不是 Google 的锅,问题出在我自己的链路上。
初步排查
先去论坛搜了一圈,发现不少人遇到过类似的问题。核心结论是:Gemini 的 UI 重度依赖 gstatic.com 上的静态资源 (字体、图标、CSS、JS),这些资源加载不出来,页面自然就炸了。 linux do
但大多数帖子的解决方案是"换个节点"或者"在客户端路由里把 gstatic.com 加上"------我试了,没用。
定位根因
既然客户端路由没问题(MATCH,Proxy 兜底规则已经把所有非国内流量都走了代理),那问题只可能出在服务端。
SSH 上去,直接 curl 一下:
perl
curl -sI --max-time 5 https://www.gstatic.com
# 超时,没有任何返性
果然连不上。再看看 DNS 解析的结果:
csharp
dig +short www.gstatic.com
# 203.208.50.162
这个 IP 一查,属于 Google 的亚太节点。一台在美国的 VPS,DNS 解析出来一个亚洲的 IP,而且还连不上------这就很离谱了。
用 Cloudflare 的 DoH 验证一下:
bash
curl -sH 'accept: application/dns-json' \
'https://cloudflare-dns.com/dns-query?name=www.gstatic.com&type=A'
# 返回 142.251.46.227
这是个正常的美国 Google IP。手动指定这个 IP 去连:
perl
curl -sI --max-time 5 \
--resolve www.gstatic.com:443:142.251.46.227 \
https://www.gstatic.com
# HTTP/2 404 ← 正常!gstatic 根路径本来就是 404
破案了:系统 DNS 返回了错误的 IP。
我这台 VPS 的 /etc/resolv.conf 用的是 8.8.8.8,但实际解析出来的 gstatic.com IP 跟 Cloudflare DoH 拿到的完全不一样。具体原因可能是 DNS 查询在链路上被污染了,或者上游解析策略有问题,总之拿到了一个从美国根本连不上的亚太 IP。
解决方案
知道了原因,修起来就简单了。分两步:
1. 修复系统 DNS
把 /etc/resolv.conf 从 8.8.8.8 改成 1.1.1.1。验证了一下,Cloudflare 的 DNS 对 gstatic.com 返回的是正确的 IP:
bash
# 修改前
nameserver 8.8.8.8
nameserver 8.8.4.4
# 修改后
nameserver 1.1.1.1
nameserver 1.0.0.1
改完验证:
csharp
dig +short www.gstatic.com
# 142.250.191.35 ← 正确的美国 IP
⚠️ 如果你的 VPS 是 SolusVM 面板管理的,
resolv.conf可能会在重启后被覆盖。可以用chattr +i /etc/resolv.conf锁定文件,或者通过面板修改 DNS 设置。
2. 给 Xray 加上 DoH DNS + 嗅探(双保险)
光改系统 DNS 能解决大部分场景,但为了更稳,我在 Xray 的配置里也加了一层保障。
核心改动有三个地方:
a) 内置 DNS,Google 域名走 DoH
json
"dns": {
"servers": [
{
"address": "https+local://cloudflare-dns.com/dns-query",
"domains": [
"gstatic.com",
"googleusercontent.com",
"googleapis.com",
"google.com"
]
},
"1.1.1.1"
]
}
指定 Google 相关的域名走 Cloudflare DoH 解析,其余域名走 1.1.1.1。DoH 走的是 HTTPS,不会被中间链路篡改。
b) 入站开启嗅探
json
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"]
}
这一步很关键。如果你的客户端用了 fake-ip 模式(比如 Clash 的默认 DNS 配置),发到服务端的目标地址其实是一个假 IP(类似 198.18.0.x),而不是真实域名。
开了嗅探之后,Xray 会从 TLS 握手的 SNI 字段里提取出真实域名(比如 www.gstatic.com),然后再用上面配置的 DoH 去解析成正确的 IP。
不开嗅探的话,前面配的 DNS 规则根本不会生效------因为 Xray 拿到的只是一个 IP 地址,匹配不到任何域名规则。这个坑我踩了好几遍才意识到。
c) freedom 出站加 UseIP
json
{
"protocol": "freedom",
"tag": "direct",
"settings": {
"domainStrategy": "UseIP"
}
}
告诉 freedom 出站:碰到域名的时候,先用 Xray 内置的 DNS 解析成 IP,再去连接。不加这个的话,freedom 默认用系统 DNS 解析,又会拿到那个错误的 IP。
完整配置
最终的 Xray 配置长这样:
json
{
"log": {
"loglevel": "warning",
"access": "/var/log/xray/access.log",
"error": "/var/log/xray/error.log"
},
"dns": {
"servers": [
{
"address": "https+local://cloudflare-dns.com/dns-query",
"domains": [
"gstatic.com",
"googleusercontent.com",
"googleapis.com",
"google.com"
]
},
"1.1.1.1"
]
},
"inbounds": [
{
"port": 10086,
"listen": "127.0.0.1",
"protocol": "vless",
"settings": {
"clients": [
{
"id": "你的UUID",
"level": 0
}
],
"decryption": "none"
},
"streamSettings": {
"network": "ws",
"wsSettings": {
"path": "/你的路径"
}
},
"sniffing": {
"enabled": true,
"destOverride": ["http", "tls", "quic"]
}
}
],
"outbounds": [
{
"protocol": "freedom",
"tag": "direct",
"settings": {
"domainStrategy": "UseIP"
}
}
]
}
改完 systemctl restart xray,清一下浏览器缓存,刷新 Gemini------图标回来了,世界清净了。
如果你没法改服务端配置怎么办?
上面的方案是在服务端解决问题。但如果你用的是第三方现成的服务,改不了服务端配置,在客户端侧也有一些办法:
方法一:本地 hosts 文件强制指定正确 IP
最暴力也最直接。手动把 gstatic.com 的正确 IP 写进系统 hosts 文件:
shell
# Windows: C:\Windows\System32\drivers\etc\hosts
# macOS/Linux: /etc/hosts
142.250.80.3 www.gstatic.com
142.250.80.3 fonts.gstatic.com
142.250.80.3 ssl.gstatic.com
142.251.46.227 googleusercontent.com
正确的 IP 可以通过 DoH 查询获取:
bash
https://cloudflare-dns.com/dns-query?name=www.gstatic.com&type=A
缺点:Google 的 IP 会变,过一段时间可能要重新查一次。但一般 Google CDN 的 IP 比较稳定,能撑挺久。
方法二:让 gstatic.com 走直连而不是代理
有些情况下,gstatic.com 从国内其实是能直连的(取决于你所在地区和运营商)。可以在客户端的路由规则里把它设成 DIRECT:
Clash 配置示例:
makefile
rules:
- DOMAIN-SUFFIX,gstatic.com,DIRECT
- DOMAIN-SUFFIX,googleusercontent.com,DIRECT
# ... 其他规则
原理:绕过有问题的代理服务器,让这些静态资源请求直接从你本地出去。gstatic.com 本身只是字体和 JS 文件,不涉及账号数据,直连问题不大。
缺点 :不是所有地区都能直连 gstatic.com。试一下,能访问 https://fonts.gstatic.com 就说明能用。
方法三:客户端 DNS 改用 DoH
如果你用的是 Clash Meta (Mihomo),可以在 DNS 配置里把 Google 相关域名的解析指定走 DoH:
bash
dns:
enable: true
enhanced-mode: fake-ip
nameserver:
- https://doh.pub/dns-query
- https://dns.alidns.com/dns-query
nameserver-policy:
"+.gstatic.com": "https://cloudflare-dns.com/dns-query"
"+.googleapis.com": "https://cloudflare-dns.com/dns-query"
"+.googleusercontent.com": "https://cloudflare-dns.com/dns-query"
nameserver-policy 可以针对特定域名指定 DNS 服务器。不过这种方式只能保证客户端侧解析正确,如果问题出在代理服务器的出口 DNS 上(就像我遇到的情况),客户端改 DNS 可能帮不上忙------因为最终请求还是从服务端出去,服务端会重新解析一次。
方法四:换个节点
没什么技术含量,但确实管用。不同节点的服务器 DNS 配置不一样,换一个可能就好了。如果你发现某个节点一直访问 Gemini 乱码,大概率就是那台服务器的 DNS 有问题,反馈给服务商让他们去修。
排查思路总结
回头看,这次排查绕了不少弯路。核心教训:
- 客户端路由规则没问题 ≠ 服务端能连上目标 。一开始在客户端侧折腾了半天,加了各种
DOMAIN-SUFFIX规则,其实根本不是客户端的锅。 - DNS 污染不只发生在客户端。服务端的 DNS 一样可能返回错误结果,尤其是用 UDP 明文 DNS 的时候。
- fake-ip + 不开嗅探 = DNS 配置白搭。这个组合是最大的坑。客户端用 fake-ip 模式发过来的是 IP 不是域名,服务端不嗅探就不知道真正要访问的是啥,配再多域名规则也没用。
- 优先用 DoH/DoT。UDP 53 端口的明文 DNS 太容易被中间人篡改了。花两分钟配个 DoH,能省很多排查时间。
如果你也遇到了类似的"某些 Google 服务页面乱码、静态资源加载失败"的问题,不妨先 SSH 到服务端 dig 一下对应域名,很可能就是 DNS 的锅。