Google Drive "Open With" App 集成踩坑实录:redirect_uri_mismatch 完整排查与修复

简介: 本文揭秘 Google Drive “打开方式”集成中 redirect_uri_mismatch 的根源:问题不在代码或配置,而在于 Drive 服务端根据旧注册信息(如 ngrok 地址)自动生成 OAuth URL。关键陷阱是已废弃的“自动显示 OAuth 授权页”选项,它将错误 redirect_uri 硬编码进服务端 Registry。修复需四步:F12 定位真实 URL → 用 apps.get 验证 Registry → 取消该选项并等待同步(或新建 GCP 项目)→ 彻底卸载重装应用。

三天时间,一个五分钟能解决的问题。根本原因是:Drive "Open With" 的 OAuth 请求压根不是你的服务器发起的。


背景:从 ngrok 调试到生产环境出了问题

最近在给自己的文档处理工具Renomee AI接入 Google Drive 集成——用户可以在 Drive 里右键文件 → "打开方式" → 选我的 App,然后触发 OAuth 授权、处理文件。

整体架构如下:

┌──────────────┐         ┌─────────────────────┐         ┌──────────────┐
│ Google Drive │         │  drive-api.renomeeai │         │  Google APIs │
│   (用户端)   │         │     (FastAPI)        │         │              │
└──────┬───────┘         └──────────┬───────────┘         └──────┬───────┘
       │                            │                             │
       │  1. 右键文件 → "打开方式"   │                             │
       │  Drive 构造 OAuth URL      │                             │
       │──────────────────────────►│                             │
       │                            │                             │
       │                            │  2. 重定向 → Google 授权页  │
       │◄───────────────────────────┼────────────────────────────│
       │  用户点击允许               │                             │
       │                            │  3. callback: code 换 token│
       │                            │───────────────────────────►│
       │                            │◄───────────────────────────│
       │                            │   access_token+refresh_token│
       │                            │                             │
       │                            │  4. 加密存 DB,下发 Cookie  │
       │◄───────────────────────────│                             │
       │                            │                             │
       │  5. 前端调 session/init     │                             │
       │──────────────────────────►│                             │
       │                            │  6. 用 token 拉文件元数据   │
       │                            │───────────────────────────►│
       │                            │◄───────────────────────────│
       │◄───────────────────────────│   files: [name, mimeType,  │
       │  { needs_auth, files }     │           imageMetadata]    │
       │                            │                             │
       │  7. 输入重命名指令          │                             │
       │──────────────────────────►│                             │
       │                            │  8. 调 RenameAI 获取建议名  │
       │                            │──────► api.renameai.com    │
       │                            │◄──────  suggested_name     │
       │◄───────────────────────────│                             │
       │  { suggested_name }        │                             │
       │                            │                             │
       │  9. 用户确认 → apply       │                             │
       │──────────────────────────►│                             │
       │                            │  10. PATCH Drive 文件名    │
       │                            │───────────────────────────►│
       │◄───────────────────────────│◄───────────────────────────│
       │  { success, new_name }     │                             │

本地开发阶段用 ngrok 做内网穿透,在 Google Cloud Console 里把 ngrok 临时地址注册为 Redirect URI,跑通了整个流程。

切换到生产环境时,我做了三件事:

  1. 在 GCP Console 把 Redirect URI 更新为正式域名
  2. 改了服务器 .env 里的 GOOGLE_DRIVE_REDIRECT_URI
  3. 重建 Docker 容器重新部署

测试时:

Error 400: redirect_uri_mismatch
The redirect URI in the request did not match a registered redirect URI.

打开 F12 → Network,找到跳转到 Google 授权页面前的那条请求,URL 里赫然写着:

redirect_uri=https://7886-45-78-56-186.ngrok-free.app/drive/open

是几个月前的 ngrok 旧地址。.env 改了,容器重建了,但这个地址没变。


排查过程:先搞清楚这个 URL 是谁构造的

直觉上以为是我服务器发出的请求,所以一直在改代码和配置。这个思路本身就错了。

实际上,Drive "Open With" 有两套完全独立的 OAuth 流程:

流程 OAuth URL 由谁构造 redirect_uri 来自哪里
你的 /auth/start 路由 你的服务器 .env 配置
Drive "Open With" 原生跳转 Google Drive 的服务器 Drive UI Integration 配置

F12 里抓到的那个 URL,是 Google 的服务器根据我当初注册 App 时的配置自动生成的。我的代码、我的 .env、我的容器,对它没有任何影响。


第一步:F12 提取真实的 redirect_uri

在排查类似问题时,第一步永远是先拿到"实际发出的 URL",而不是看代码里写了什么。

  1. Google Drive 右键文件 → 打开方式 → 点你的 App
  2. 报错页面出现之前,打开 DevTools(F12)→ Network 标签
  3. 过滤 accounts.google.com
  4. 找到那条跳转请求,复制完整 URL

你会看到一个类似这样的完整 URL:

https://accounts.google.com/o/oauth2/auth
  ?scope=https://www.googleapis.com/auth/drive.file
  &client_id=YOUR_CLIENT_ID.apps.googleusercontent.com
  &response_type=code
  &access_type=offline
  &redirect_uri=https://7886-45-78-56-186.ngrok-free.app/drive/open   ← 问题就在这里
  &state=%7B%22ids%22%3A%5B%22xxx%22%5D%2C%22action%22%3A%22open%22%2C%22userId%22%3A%22xxx%22%7D

注意 redirect_uri 参数——如果它是一个旧的 ngrok 地址或其他已失效的域名,说明这个 URL 不是你的服务器构造的,而是 Google 服务端根据历史注册信息生成的。

用脚本提取 redirect_uri:

python3 -c "
import urllib.parse as u
url = '粘贴完整的 URL'
qs = u.parse_qs(u.urlparse(url).query)
print('redirect_uri:', qs.get('redirect_uri', ['未找到'])[0])
"

如果看到的是旧地址、ngrok 地址或其他错误域名,继续往下。


第二步:查询 Drive App Registry(权威数据源)

GCP Console 显示的是"你提交的配置"。Drive API 的 apps.get 接口返回的,才是"Google Drive 服务器实际在用的配置"。两者之间存在同步延迟,有时甚至永远不同步。

通过 OAuth Playground 获取 Access Token

  1. 打开 developers.google.com/oauthplayground
  2. 右上角 ⚙️ → 可选填入自己的 Client ID / Secret
  3. 左侧 Step 1 输入 scope,点 Authorize APIs:
    https://www.googleapis.com/auth/drive.apps.readonly
    
  4. 完成授权后点 Exchange authorization code for tokens
  5. 复制 Access token

查询你的 App 配置

TOKEN="你的 access token"
APP_ID="YOUR_PROJECT_NUMBER"  # GCP 项目编号(纯数字),不是项目 ID

curl -s \
  -H "Authorization: Bearer $TOKEN" \
  "https://www.googleapis.com/drive/v3/apps/$APP_ID?fields=id,name,openUrlTemplate,installed,authorized" \
  | python3 -m json.tool

GCP 项目编号(projectNumber)和项目 ID(projectId)是两回事,用 gcloud projects describe YOUR_PROJECT_ID --format="value(projectNumber)" 获取。

在 openUrlTemplate 字段找到了问题所在。

我的响应是这样的:

"openUrlTemplate": "https://accounts.google.com/o/oauth2/auth?scope=...&redirect_uri=https://7886-45-78-56-186.ngrok-free.app/drive/open&..."

Google 把我几个月前的 ngrok 地址硬编码进了这个模板,存在它的服务端。每次用户触发"打开方式",Drive 就用这个模板构造 OAuth URL,所以我怎么改本地配置都没有用。


第三步:找到真正的配置入口

Google Cloud Console
  → APIs & Services
  → Enabled APIs & Services
  → Google Drive API(点击进入)
  → Drive UI Integration 标签页

问题根源:一个被废弃的选项

在这个页面里找这个复选框:

☐ Automatically show OAuth 2.0 consent screen when users open
  my application from Google Drive

我的 App 勾选了这个选项。这是根本原因之一。

这个选项勾选后,Drive 不会把用户直接发送到你的 Open URL,而是先构造一个 OAuth 包装 URL,其中的 redirect_uri 就是你当时注册时填的地址(在我的情况下是 ngrok)。这个包装 URL 会被写入 Drive App Registry 的 openUrlTemplate 字段,存储在 Google 服务端。

Google 已经正式废弃了这个选项,但很多老教程里仍然推荐勾选它,踩坑的人因此前赴后继。

第一步:取消勾选,保存,同时确认 Open URL 正确。

Open URL: https://your-domain.com/drive/open

⚠️ 注意:这只是必要条件,不是充分条件。

取消勾选后,你的"提交配置"是正确的了,但 Drive App Registry 里已经存了旧的 openUrlTemplate。这两件事是独立的: 复选框控制"未来是否继续生成包装 URL",Registry 缓存控制"现在实际生效的 URL"。

保存后必须用 apps.get 验证 Registry 是否已经同步,不能只看 Console 页面。


第四步:验证配置是否同步到 Registry

保存后,每隔 10 分钟重新跑一遍 Step 2 的 apps.get 查询。

期望看到的响应:

"openUrlTemplate": "https://your-domain.com/drive/open?state={ids}&action={action}&userId={userId}"

不再有 OAuth 包装 URL,不再有旧地址。

如果超过 1 小时仍然是旧值,不要再等了。 直接跳到文末"当一切方法都无效时"章节。旧项目的 Registry 有可能就是不会同步,继续等只是浪费时间。


第五步:重新安装 App

这里还有一个坑:即使 Registry 里的配置已经更新,之前用旧配置安装过 App 的账号,仍然在使用旧的安装状态。必须完整走一遍卸载-重装流程。

正确的重装顺序(顺序不能错):

  1. Google Drive 设置 → 管理应用 → 找到你的 App → 断开连接
  2. myaccount.google.com/connections → 找到 App → 移除访问权限
  3. 重新执行 apps.get,确认 installed: false
  4. 等到 apps.get 返回新配置后,再重新触发授权
  5. 如果在第 4 步完成前就重新授权,会再次安装旧配置

第 4 步是个隐性依赖。我在第一次修复后跳过了这一步,导致安装了旧配置,又花了大半天才发现。


附:新增文件类型不出现在菜单

在修复 OAuth 问题的同时,我还需要给 App 增加图片支持(jpeg、png 等)。MIME 类型加到 Console 里之后,图片文件的右键菜单里就是不出现我的 App。

原因:已安装的 App 实例不会自动拉取新的 MIME 类型配置,必须按上面的顺序完整走一遍卸载重装。

另外,文件类型建议放在 Secondary(次要)而不是 Default(默认),避免把你的 App 设置为默认打开方式:

Secondary MIME Types:
  application/pdf
  image/jpeg / image/png / image/webp

Secondary File Extensions:
  pdf / jpg / jpeg / png / webp

当一切方法都无效时:新建 GCP 项目

如果保存配置超过 1 小时,apps.get 仍然返回旧的 openUrlTemplate,说明这个项目的 App Registry 条目可能陷入了一种卡死状态。

方式 A:禁用再启用 Drive API(有时有效)

gcloud services disable drive.googleapis.com --project=YOUR_PROJECT_ID
gcloud services enable drive.googleapis.com --project=YOUR_PROJECT_ID

重新保存 Drive UI Integration,再查询。不保证有效。

方式 B:新建 GCP 项目(推荐,这才是真正解决问题的方式)

在旧项目上耗了将近一天之后,我新建了一个 GCP 项目。第一次查询 apps.get 就立即返回了正确的 openUrlTemplate,整个流程第一次就跑通了。事后来看,遇到 Registry 不同步时,新建项目比等待节省的时间不是一星半点。

# 创建新项目
gcloud projects create my-app-drive-prod --name="My App Drive Prod"

# 启用 Drive API
gcloud services enable drive.googleapis.com --project=my-app-drive-prod

# 获取项目编号(用于 apps.get 查询)
gcloud projects describe my-app-drive-prod --format="value(projectNumber)"

在新项目里按正确顺序配置:

  1. OAuth consent screen → External → 添加测试用户
  2. Credentials → Create OAuth Web Client → 填写正确的 Redirect URI
  3. Drive UI Integration → 不勾选自动 OAuth → 填写 Open URL 和 MIME 类型

新项目没有任何历史 Registry 条目,apps.get 保存后立即返回正确值。

更新服务器配置:

GOOGLE_DRIVE_CLIENT_ID=新的 Client ID
GOOGLE_DRIVE_CLIENT_SECRET=新的 Client Secret

重建容器:

docker compose up -d --force-recreate app

排查流程图

出现 redirect_uri_mismatch
         ↓
F12 → Network → 提取 redirect_uri
         ↓
是旧地址 / ngrok / 错误域名?
         ↓ 是
OAuth Playground 获取 token → GET /drive/v3/apps/{appId}
         ↓
openUrlTemplate 是 OAuth 包装 URL?
         ↓ 是
Drive UI Integration
  → 取消勾选"Automatically show OAuth 2.0 consent screen"
  → 确认 Open URL 正确 → 保存
         ↓
每 10 分钟查一次 → apps.get 是否更新?
    ↓ 否(超过 1 小时)       ↓ 是
新建 GCP 项目              完整走卸载重装流程
(立即生效)               (断开 → 撤权 → 等 apps.get 更新 → 重新授权)

总结

  • 先用 F12 看实际发出的 URL,不要猜,不要看代码
  • Drive "Open With" 的 OAuth URL 由 Google 的服务器构造,与你的代码和 .env 无关
  • 根本原因几乎一定是 "Automatically show OAuth 2.0 consent screen" 被勾选了——这导致错误的 redirect_uri 被写入 Registry
  • 取消勾选是必要条件,不是充分条件:复选框和 Registry 缓存是两个独立问题
  • 配置是否生效,唯一可信来源是 GET /drive/v3/apps/{appId},不是 Console 页面
  • 取消勾选后 Registry 不一定立即更新,超过 1 小时不更新就直接新建 GCP 项目
  • 新项目没有历史缓存,配置保存后立即生效,是最快的修复路径

相关参考:Google Drive API — Enable the Drive UI

相关文章
|
13天前
|
Linux 开发工具 iOS开发
Codex保姆级教程(下载+安装+登录+使用,含所有版本,2026最新)
Codex是OpenAI推出的开源AI编程智能体,本地运行,可理解整个代码库,支持自然语言指令改代码、执行命令、跑测试、修Bug,兼容Win/macOS/Linux。(239字)
5549 41
|
14天前
|
JavaScript API iOS开发
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(DSH)是DeepSeek于2026年开源的MIT协议AI Agent框架,支持插件化组装模型、工具、沙箱与UI,兼容主流大模型。本文提供免Node.js的桌面端安装包(Win/macOS),含详细图文教程及热门插件推荐。
4816 58
|
8天前
|
Linux 开发工具 iOS开发
2026最新codex下载安装保姆级使用教程(下载+安装+登录+使用,含所有历史版本)
本文详解OpenAI Codex国内快速上手指南:提供Win/macOS/Linux全平台免安装包、npm/Homebrew等多方式安装、账号/API Key双登录、简体中文切换,覆盖下载、安装、汉化、使用及高频避坑(如微软商店失败、npm超时等),10分钟即可跑通。
2105 6
|
14天前
|
iOS开发 Docker MacOS
【2026实测】Docker Desktop下载、安装、汉化、配置教程(附官网安装包)
Docker Desktop 是 Docker 官方推出的桌面容器管理工具,集成引擎、CLI、图形界面与 Kubernetes,支持 Win/macOS/Linux。2026 最新版 4.88.1 强化 ARM 原生运行、镜像加速及资源可视化,附中文汉化与国内镜像配置指南。
2291 7
|
6天前
|
人工智能 安全 API
DeepSeek Harness下载、安装、配置一篇搞定(2026整理,送常用插件)
DeepSeek Harness(dsh)是DeepSeek AI于2026年开源的轻量级Agent运行框架,基于Cordis内核,践行“一切皆插件”理念。支持Web/桌面双端,开箱即用;内置多模型接入、丰富插件生态(超3.5万),适配编程、办公、创作等场景。(239字)
1305 0
|
8天前
|
云安全 人工智能 安全
|
1天前
|
云安全 人工智能 安全
|
7天前
|
人工智能 并行计算 调度
本地 AI 一键部署工具 LocModel:Windows 端集成画图、视频生成、Agent 的开源模型运行方案
LocModel 是专为 Windows 设计的一站式本地 AI 工具,支持零配置启动、自动硬件检测、GGUF 模型一键加载、文生图/视频生成及 Agent 自动化任务。适配 8G 显存,内置显存分片调度,轻松实现 AI 漫剧批量创作与离线大模型调用。(239 字)

热门文章

最新文章