---
author: OOMOL
author_url: https://oomol.com/zh-cn/about/
title: 通过 SaaS Proxy 调用厂商 API
description: 使用 Project API key 和终端用户已连接的账号，通过 SaaS Proxy 调用厂商 API。
lang: zh-CN
canonical_url: https://oomol.com/zh-cn/docs/saas-proxy/
markdown_url: https://oomol.com/zh-cn/docs/saas-proxy.md
---

# 通过 SaaS Proxy 调用厂商 API

需要调用尚未封装为 Connector 操作的厂商接口时，可以使用 SaaS Proxy。后端指定接口地址、方法和参数，Connector 选择终端用户已连接的账号并注入厂商凭证。厂商必须支持 proxy，调用仍受账号已有权限约束。

## 准备已连接的账号

先完成 [Connector for SaaS 接入指南](/zh-cn/docs/connector-saas/)，将 Project API key 保存在后端，并保存经过验证的用户与账号绑定关系。使用 oo_proj_… 形式的 Project key，不要使用 OOMOL 个人 key 或厂商 token。根据产品已登录用户确定 userId 和账号，不要直接信任浏览器提交的任意账号 ID。

## 通过 HTTP 调用

```http
POST https://connector.oomol.com/v1/saas/proxy/{service}
Authorization: Bearer <project-api-key>
Content-Type: application/json
```

下面的 Gmail 只读示例获取已连接账号的个人资料。将服务配置和连接账号 ID 替换为后端保存的值，账号需已授权读取资料。外层 HTTP 方法始终为 POST，厂商请求的方法写在 request 内。

```bash
export PROJECT_API_KEY='oo_proj_...'
export PROVIDER_CONFIG_ID='<gmail-provider-config-id>'
export CONNECTED_ACCOUNT_ID='<connected-account-id>'

curl --silent --show-error \
  'https://connector.oomol.com/v1/saas/proxy/gmail' \
  -H "Authorization: Bearer $PROJECT_API_KEY" \
  -H 'Content-Type: application/json' \
  -H 'x-request-id: req-saas-proxy-1' \
  --data @- <<JSON
{
  "providerConfigId": "$PROVIDER_CONFIG_ID",
  "userId": "customer-1",
  "connectedAccountId": "$CONNECTED_ACCOUNT_ID",
  "request": {
    "endpoint": "/users/me/profile",
    "method": "GET"
  }
}
JSON
```

## 请求字段

| 字段 | 用法 |
| --- | --- |
| `userId` | 必填：产品内的终端用户 ID，必须与连接账号对应。 |
| `providerConfigId` | 可选，推荐显式填写服务配置 ID，其服务必须与 URL 一致。省略时，项目中该服务必须只有一个有效配置。 |
| `connectedAccountId` / `alias` | 可选，最多填写一个。都省略时，选择该用户在此服务配置下最新的 active 账号。 |
| `request.endpoint` | 必填：以 / 开头、拼接到厂商 Base URL 后的路径，或位于允许来源的完整 HTTPS URL。Gmail 的 Base URL 为 https://gmail.googleapis.com/gmail/v1。 |
| `request.method` | 必填：GET、POST、PUT、PATCH 或 DELETE。 |
| `request.query` | 可选：值为字符串、数字、布尔值或 null 的对象。null 项会被跳过，不接受数组或嵌套对象。 |
| `request.headers` | 可选：非鉴权请求头。Connector 会注入凭证，不要填写 Authorization、Cookie、Host 或 X-API-Key。 |
| `request.body` | 可选：发送给厂商写入接口的 JSON 或文本。GET 不发送请求体。 |

## 通过 ProjectConnector 调用

使用包含 ProjectConnector.proxy 的 @oomol-lab/connector 版本。如果已安装版本没有此方法，可先使用 HTTP 示例。SDK 使用 externalUserId 和 connectionName，发送时转换为 userId 和 alias；connectedAccountId 优先于 connectionName。泛型用于描述预期响应类型，不会在运行时验证厂商数据。

```sh
npm install @oomol-lab/connector
```

```ts
import { ProjectConnector } from "@oomol-lab/connector";

const project = new ProjectConnector({
  apiKey: process.env.PROJECT_API_KEY!,
});

const result = await project.proxy<{ emailAddress: string }>(
  "customer-1",
  "gmail",
  { endpoint: "/users/me/profile", method: "GET" },
  {
    providerConfigId: process.env.PROVIDER_CONFIG_ID!,
    connectedAccountId: process.env.CONNECTED_ACCOUNT_ID!,
    retries: 0,
  },
);

if (result.status < 200 || result.status >= 300) {
  throw new Error(`Provider returned HTTP ${result.status}`);
}
console.log(result.data.emailAddress);
```

同一用户需要多次调用时，可以先绑定用户：

```ts
const user = project.forUser("customer-1");
const profile = await user.proxy<{ emailAddress: string }>(
  "gmail",
  { endpoint: "/users/me/profile", method: "GET" },
  {
    providerConfigId: process.env.PROVIDER_CONFIG_ID!,
    connectionName: "work",
    retries: 0,
  },
);
if (profile.status < 200 || profile.status >= 300) {
  throw new Error(`Provider returned HTTP ${profile.status}`);
}
console.log(profile.data.emailAddress);
```

## 读取响应与处理错误

下面是 HTTP 响应结构示例。SDK 直接返回其中的 data 对象，即 status、headers 和 data。通过 HTTP 调用时，可保存 meta.executionId 用于排查。

```json
{
  "success": true,
  "message": "OK",
  "data": {
    "status": 200,
    "headers": { "content-type": "application/json" },
    "data": {
      "emailAddress": "user@example.com",
      "messagesTotal": 120,
      "threadsTotal": 80,
      "historyId": "12345"
    }
  },
  "meta": {
    "executionId": "exec-example",
    "service": "gmail",
    "appId": "app-example"
  }
}
```

需要检查两层结果。Connector 成功返回时，data.status 仍可能是厂商的非 2xx 状态码；SDK 对应检查 result.status，同时检查厂商响应体。Connector 自身的失败会在 SDK 中抛出 ConnectorError。Project API key 无效时，HTTP 可能返回 401 和纯文本 Unauthorized，因此不要假定所有错误响应都是 JSON。

## 限制与排查

- Proxy 返回解析后的 JSON 或文本，不是流式或二进制传输接口。默认上游超时为 30 秒，响应大小限制为 4 MiB；具体厂商可以覆盖这些限制。

- Proxy 不会增加 OAuth 权限。厂商因 scope 不足拒绝请求时，检查服务配置，并让用户重新授权所需权限。只接受厂商允许的来源，不能代理任意 URL。

- provider_config_not_found 和 multiple_provider_configs_found 用于排查配置选择；proxy_not_supported 表示厂商不支持 proxy。遇到 proxy_upstream_timeout 或 proxy_response_too_large 时，尽可能缩小请求或响应范围。

- 超时不代表厂商写入失败。可能产生重复效果的操作应关闭自动重试，SDK 示例已将 retries 设为零。记录请求 ID 和 HTTP 响应中存在的 meta.executionId，并到 OOMOL Console 的项目执行记录中排查。

继续阅读 [ProjectConnector 账号接入](/zh-cn/docs/project-connector/)。
