为什么 Apps Script 无法通过 VPN 访问你的内部应用
Apps Script 运行在 Google 的网络上,而不是持有 VPN 的笔记本上。请为发起请求的那台机器设计数据路径。
仪表盘在笔记本的浏览器里打开一切正常,可同一个表格脚本却报地址不可用。切换 VPN 没有任何变化,因为请求根本没有从笔记本发出。Apps Script 在 Google 的基础设施上执行,并从那里建立自己的连接。仅这一点就决定了整个设计。
动手改动之前,先把两个问题分开:哪台机器发出请求,接收方接受哪种凭据。
请求从不在你的笔记本上发起
浏览器标签从笔记本出发,经过 VPN 适配器、内部 DNS 后缀,进入私有子网。UrlFetchApp 从 Google 管理的宿主机发出,因此它看到的是 Google 的解析器和出口地址,而你的一条分流路由都看不到。两条路径共享的是一份表格文档,而不是同一个网络位置。在应用访问日志里,脚本的尝试会显示为 Google 地址,而不是 VPN 池地址,这是你能拿到的最快确认。
所以本地修补毫无作用。把笔记本指向别的解析器、重启 VPN 客户端、或在 hosts 里加一行,只会改变浏览器的路径,脚本的路径原封不动。
这排除了什么
只允许内部访问的端点无法从 Apps Script 到达,而 IP 白名单在这个位置是访问控制的弱替代品。Google 的出口网段范围很宽、与其他客户共用,也无法绑定到某一个脚本。UrlFetchApp 参考文档指出请求源自 Google 的 IP 池,这是该说法最权威的版本。把内部应用对这些网段开放,等于放进你无法归因的流量。
浏览器会话也是如此。笔记本浏览器里的 Cookie 或 SSO 会话不会随请求一起过去,因为请求是一个没有会话状态的全新 HTTPS 客户端。任何依赖浏览器 SSO 重定向的东西,都会止步于那次重定向,而到不了你的数据。
两种可行的形态
第一种给脚本一个受认可的 API。把内部服务发布在会认证调用方的网关之后,再让脚本出示网关接受的凭据,比如服务账号令牌。在 Apps Script 里,这意味着 OAuth2 库或 ScriptApp.getOAuthToken(),并在 API 侧用调用方身份白名单取代 IP 名单。
第二种把方向反过来。让内部任务查询私有系统,把受控的结果发布到脚本可读取的 Sheet、Cloud Storage 对象或 BigQuery 表。Cloud Run 任务、本地调度器或既有的 ETL 步骤都可以承担这个任务,而且都不必接受入站连接。表格消费的是数据集,而不是接口。
哪种形态胜出,取决于新鲜度、字段级控制,以及谁必须能审计读取方。
发布的结果必须包含什么
反向馈送需要一份明确契约:承载的字段、刷新间隔、读取方分组,以及内部任务失败时该怎么办。缺了这四项,表格会安静地显示昨天的数字。加上生成的时戳列和行数,让过期或部分发布在表里就能看出来,不必有人去翻日志。
API 方向同样需要契约:网关接受哪种凭据、令牌携带哪些 scope、允许哪些调用方身份。含登录页的 200 响应并不算成功调用,所以要检查响应体,而不只是状态码。
从正确的一侧读错误
Apps Script 把无法访问的宿主机报成地址不可用的异常,这并非浏览器的连接被拒消息。网关返回 403 说明请求到了,但凭据或策略被拒。HTML 登录页说明请求抵达了一个脚本无法完成的交互层。三种不同的失败,三个不同的责任人。
把脚本日志放在浏览器结果旁边,而不是用一方替代另一方。剩下的问题就只是一个普通的集成决策:给那个环境所需的访问权限,或者向它交付受控的结果。