Google OAuth 2.0 接入失败排查笔记:从环境变量到 TUN 模式

6 分钟

最近在项目中接入 Google OAuth 2.0 登录功能时,遇到了一个比较典型的网络连接问题。

现象是: 我的电脑开启了 Clash 的系统代理,浏览器可以正常访问 Google,但后端代码在请求 oauth2.googleapis.com 验证 Token 时,总是报错 Connection Timed Out

为了解决这个问题,我从系统代理开始,一路排查到了 TUN 模式,并更换了代理软件。这是一篇关于这次排查过程的记录。


一、 系统代理 (System Proxy) 的局限

刚开始使用代理软件时,通常只开启“System Proxy”。

它的实际作用: 它仅仅是修改了操作系统的网络设置(例如 Windows 的“代理”设置页,或 macOS 的“网络”设置),填入了一个 HTTP 代理地址(通常是 127.0.0.1:7890)。

适用范围:

  • 生效: 浏览器(Chrome, Edge, Safari)和部分系统自带应用。它们在发起网络请求前,会主动去读取系统的代理设置。
  • 无效: 终端(Terminal)、命令行工具、大部分编程语言的运行环境(如 Python, Java, Node.js 的某些请求库)。

局限性: 这也是为什么浏览器能访问 Google,但在终端执行 git clone 或者 ping 时依然无法连接的原因。


二、 尝试解决:环境变量

既然终端不认系统设置,通常的办法是手动设置环境变量 http_proxyhttps_proxy

为了方便在终端切换代理状态,我参考网上的方法,在 ~/.zshrc 配置文件中写入了两个函数,避免每次都要手动输入一长串 export 命令:

Bash

# ~/.zshrc 文件内容

# 开启代理 (端口需根据实际情况调整,例如 Clash 默认是 7890)
function proxy_on() {
    export http_proxy=http://127.0.0.1:7890
    export https_proxy=http://127.0.0.1:7890
    export all_proxy=socks5://127.0.0.1:7890
    echo "Terminal Proxy: ON"
}

# 关闭代理
function proxy_off() {
    unset http_proxy
    unset https_proxy
    unset all_proxy
    echo "Terminal Proxy: OFF"
}

适用范围:* 添加并 source 之后,当需要开启代理可执行 proxy_on 命令,很多开发工具(如 npm, curl)就会生效了。

  • npm: npm 在安装包时,会优先读取 http_proxy 环境变量。所以设置后,npm install 的速度会明显提升。
  • curl / wget: 这些基础工具通常也支持读取环境变量。

但是,Google OAuth 的代码依然报错。


三、 但代码库不读取环境变量

排查发现,Google OAuth 相关的 SDK 或某些底层的 HTTP 客户端(取决于具体语言实现),在发起请求时,默认并不检查系统的环境变量

这就陷入了一个两难的境地:

  1. 要么我在代码里显式地创建一个 Proxy Agent,并注入到每一个请求中(侵入性太强,配置麻烦)。
  2. 要么寻找一种更底层的代理方式,让代码“无感”地走代理。

四、 更换软件并开启 TUN 模式

为了彻底解决这个问题,我决定尝试 TUN 模式

软件更换: 我之前使用的是 ClashX,它对 TUN 模式的支持(或配置方式)在旧版本中不够直观。因此,我卸载了 ClashX,换成了开源社区推荐的 Clash Verge。Clash Verge 基于 Clash Meta 内核,对 TUN 模式的支持非常完善。

TUN 模式原理:

在 Clash Verge 中开启 TUN 模式后,软件会创建一个虚拟网卡(在 macOS 上通常叫 utun 接口),并修改系统的路由表。

  • 以前: 流量需要应用主动配合走代理端口。
  • 现在: 操作系统会将默认的外部流量全部路由到这个虚拟网卡。

结果: 开启 TUN 模式后,Clash 在网络层直接接管了所有流量。 我清除了终端的环境变量(执行 proxy_off),还原了代码配置。再次运行项目,Google OAuth 的请求成功通过。 对于代码来说,它以为自己发出的只是一个普通的直连请求,但实际上数据包在网卡层面已经被 Clash 捕获并转发了。

总结

通过这次排查,我将代理的生效层级归纳如下:

  1. System Proxy: 解决浏览器的访问需求。
  2. 环境变量 (http_proxy): 解决大部分终端命令(如 npm, curl)的需求。
  3. 命令参数 (--proxy): 解决不支持环境变量的特定工具。
  4. TUN 模式: 解决代码库、不支持代理的软件、Ping 命令以及所有“漏网之鱼”。

如果在开发过程中遇到网络层面的“玄学”问题,建议直接检查是否开启了 TUN 模式,这通常能节省很多排查配置的时间。