登录与 API 对接
理解桌面端如何连接后端:环境变量、Auth 客户端、API 客户端、Origin 配置和完整验证流程
你将学到
- 桌面端 WebView 怎样和 01MVP Hono 后端通信
- 两个关键环境变量分别控制什么
- auth-client 和 api-client 各自的职责和配置方式
- DESKTOP_ALLOWED_ORIGINS 在 CORS 和登录中扮演的角色
- 按什么顺序逐项验证连接是否正常
整体架构
桌面端的本质是一个本地 WebView 窗口。它和浏览器一样发 HTTP 请求,但 origin 不同——浏览器预览跑在 http://localhost:7410,Tauri 原生窗口跑在 tauri://localhost 或 http://tauri.localhost。
请求链路:
WebView (React 前端)
↓ fetch / credentials: "include"
Hono 服务 (http://localhost:7001/api)
├── /auth → Better Auth 处理登录、会话、OAuth 回调
└── /rpc → oRPC 处理业务 API 调用两个端点的地址都从 VITE_DESKTOP_SERVER_URL 派生。客户端代码在:
| 文件 | 职责 |
|---|---|
src/lib/auth-client.ts | 登录、注册、会话、OAuth |
src/lib/api-client.ts | 业务 API(health、billing、account 等) |
src/config/desktop-env.ts | 环境变量读取和 Zod 校验 |
所有路径相对于 products/01mvp/apps/desktop/。
环境变量
桌面端需要两个公开环境变量。复制模板文件后编辑:
cp products/01mvp/apps/desktop/.env.example products/01mvp/apps/desktop/.env.local| 变量 | 默认值 | 说明 |
|---|---|---|
VITE_DESKTOP_SERVER_URL | http://localhost:7001/api | API 基础地址,必须以 /api 结尾 |
VITE_DESKTOP_WEB_URL | http://localhost:7001 | 网页入口,不带 /api,用于打开价格页、用户后台等 |
VITE_DESKTOP_SERVER_URL 同时决定 auth 端点(/api/auth)和 oRPC 端点(/api/rpc)。两个客户端内部都会自动拼接,你不需要分别配置。
VITE_DESKTOP_* 会进入前端 bundle。数据库连接串、支付密钥、Better Auth secret 等服务端变量不能放在这里。
Auth 客户端
src/lib/auth-client.ts 使用 Better Auth 的 React 客户端:
import { createAuthClient } from "better-auth/react";
export const desktopAuthClient = createAuthClient({
baseURL: joinUrlPath(DESKTOP_ENV.VITE_DESKTOP_SERVER_URL, "auth"),
fetchOptions: {
credentials: "include",
},
});关键点:
baseURL指向http://localhost:7001/api/authcredentials: "include"让浏览器/WebView 自动携带 cookie,这是 session 认证的前提- 模板导出了
DesktopAuthSession类型,供组件里做类型推断
登录流程:桌面端调用 desktopAuthClient.signIn.email() 或 desktopAuthClient.signIn.social() → 后端 Better Auth 创建 session → cookie 写入 WebView → 后续请求自动带上。
API 客户端
src/lib/api-client.ts 使用 oRPC 的 fetch link:
const link = new RPCLink({
fetch(url, requestOptions) {
return fetch(url, {
...requestOptions,
credentials: "include",
});
},
url: joinUrlPath(DESKTOP_ENV.VITE_DESKTOP_SERVER_URL, "rpc"),
});模板默认注册了三个 API 调用,可以用来验证整条链路:
| 调用 | 权限 | 用途 |
|---|---|---|
health.live | 公开 | 后端是否活着 |
billing.plans | 公开 | 价格数据能否返回 |
account.profile | 需要登录 | session 和 cookie 是否生效 |
先用 health.live 确认后端可达,再用 account.profile 确认登录链路完整。
Origin 配置
后端需要认识桌面端的 origin,否则 CORS 和 Better Auth 都会拒绝请求。
在 products/01mvp/packages/config/.env 里:
DESKTOP_ALLOWED_ORIGINS="http://localhost:7410,http://127.0.0.1:7410,tauri://localhost,http://tauri.localhost"这个变量被两处读取:
packages/auth/src/index.ts— Better Auth 的 trusted originsapps/web/src/server/hono.ts— CORS 中间件
不同场景对应的 origin:
| 场景 | Origin |
|---|---|
浏览器预览 (vpr @01mvp/desktop#dev) | http://localhost:7410 |
| Tauri 原生窗口 | tauri://localhost 或 http://tauri.localhost |
| OAuth 回调 | 取决于 Better Auth 配置的回调地址 |
| 生产环境 | 你实际分发的桌面 origin |
本地开发默认值已经覆盖常见情况。如果你修改了桌面端 dev server 端口,或在生产使用自定义 origin,要把对应的值加进去。每次改完后端的 env 文件,记得重启后端服务。
验证流程
后端是否可达
先确认 01MVP Web/API 已启动,然后直接请求 health 端点:
curl http://localhost:7001/api/rpc/health/live返回成功说明后端在跑,网络没问题。
登录能否完成
打开桌面端浏览器预览或 Tauri 窗口,用测试账号登录。登录成功后,检查浏览器 DevTools 的 Application > Cookies 里有没有 session cookie。
受保护 API 能否访问
登录后调用 account.profile。如果能拿到用户信息,说明 credentials: "include" 和 origin 配置都正确。
生产地址是否正确
把 VITE_DESKTOP_SERVER_URL 改成正式后端地址,重新构建桌面端,重复以上三步。生产环境的 DESKTOP_ALLOWED_ORIGINS 必须包含桌面端实际使用的 origin。
常见问题
health 正常,但 profile 返回 401
health 是公开端点,不需要 session。profile 需要登录态。按顺序排查:
DESKTOP_ALLOWED_ORIGINS是否包含了你当前的桌面 originVITE_DESKTOP_SERVER_URL是否以/api结尾- 请求头里有没有带 cookie(DevTools > Network > 点击请求 > Headers)
- 后端是否重启过,新的 env 是否已经生效
浏览器里正常,Tauri 窗口里失败
浏览器预览跑在 http://localhost:7410,Tauri 窗口跑在 tauri://localhost。如果 DESKTOP_ALLOWED_ORIGINS 只配了浏览器的 origin,Tauri 窗口里的请求会被 CORS 拒绝。确保两个 origin 都加进去。
OAuth 回调打不开或显示空白
OAuth 登录需要浏览器跳转。在 WebView 里,Better Auth 会尝试打开系统浏览器完成 OAuth 流程,然后通过 deep link 回到桌面应用。如果回调地址配置不对或 deep link 没注册,用户会看到空白页。先确认 Better Auth 的回调 URL 和 Tauri 的 URL scheme 配置一致。
下一步
登录和 API 都跑通后,下一步了解 Tauri 原生能力:Runtime 与权限。
这篇文档有问题?