---
name: leoyeai/Feishu Cloud Drive
source: https://app.decimal.ai/s/leoyeai-feishu-cloud-drive@1/SKILL.md
source_sha256: f0486b1a7548
---

# 🎯 项目起源

本技能参考了社区中的 `feishu-drive` 技能，但在实现过程中发现原技能存在以下问题：

1. **API 接口错误**：使用了错误的 API 路径（如 `GET /open-apis/drive/v1/files/:token/children` 应改为 `drive/explorer/v2` 版本）
2. **文档与实际不符**：SKILL.md 中描述的 API 与飞书官方文档不一致
3. **权限管理缺失**：创建的文件夹默认只有机器人可见，未处理权限问题

因此基于飞书官方文档重新开发了此技能，修复了所有已知问题，并新增了权限管理功能。

---

# 飞书云盘管理 (官方API版本)

你是飞书云盘管理专家，负责通过飞书官方 API 实现文件列表查询、上传、下载和文件夹管理。

## 使用方式

### 1. 配置环境变量

设置环境变量：

```bash
export FEISHU_APP_ID="your_app_id"
export FEISHU_APP_SECRET="your_app_secret"
export FEISHU_ROOT_FOLDER_TOKEN="your_folder_token"  # 可选：指定默认根目录
```

### 2. 设置根目录（推荐）

**在使用技能之前，先指定一个根目录**，后续所有操作都以此目录为基准：

```python
from feishu_drive_client import create_client, FeishuDriveClient
import os

# 方式1：使用便捷函数（推荐）
# 自动从环境变量 FEISHU_APP_ID, FEISHU_APP_SECRET, FEISHU_ROOT_FOLDER_TOKEN 读取
client = create_client()

# 方式2：手动创建客户端，从环境变量读取
client = FeishuDriveClient(
    app_id=os.getenv("FEISHU_APP_ID"),
    app_secret=os.getenv("FEISHU_APP_SECRET"),
    root_folder_token=os.getenv("FEISHU_ROOT_FOLDER_TOKEN")  # 可选
)

# 方式3：手动指定所有参数
client = FeishuDriveClient(
    app_id="your_app_id",
    app_secret="your_app_secret",
    root_folder_token="your_folder_token"  # 可选
)

# 方式4：后续动态设置根目录
client = FeishuDriveClient(app_id, app_secret)
client.set_root_folder("your_folder_token")
```

### 3. 使用示例

设置根目录后，所有操作默认在根目录下进行：

```python
# 在根目录下创建子文件夹（无需传入 folder_token）
result = client.create_folder("新文件夹")

# 在根目录下上传文件
result = client.upload_file("/path/to/file.jpg")

# 列出根目录内容
result = client.list_folder()

# 如需操作其他目录，可临时指定 folder_token
result = client.create_folder("其他位置的文件夹", parent_folder_token="其他token")
```

**优先级规则**：`传入的 folder_token` > `设置的 root_folder_token` > `空字符串（根目录）`

---

## API 基础信息

| 项目 | 值 |
|------|---|
| Base URL | `https://open.feishu.cn/open-apis/drive/v1` |
| 认证方式 | `Authorization: Bearer {tenant_access_token}` |
| Content-Type | `application/json` (文件上传用 `multipart/form-data`) |

---

## 核心功能

### 1. 获取根文件夹 Token

**接口说明**: 获取用户"我的空间"根文件夹的元数据

```
GET /open-apis/drive/explorer/v2/root_folder/meta
```

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "token": "nodcnXXXXXX",
    "id": "7110173013420512356",
    "user_id": "7103496998321312356"
  },
  "msg": "success"
}
```

**注意事项**:
- 需要权限: `drive:drive` 或 `drive:drive.metadata:readonly`
- 返回的 token 可用于后续的文件夹操作

---

### 2. 创建文件夹

**接口说明**: 在指定父文件夹下创建新文件夹

```
POST /open-apis/drive/v1/files/create_folder
```

**请求参数**:
```json
{
  "name": "文件夹名称",
  "folder_token": "父文件夹token"
}
```

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "token": "fldcnXXXXXX",
    "url": "https://xxx.feishu.cn/drive/folder/fldcnXXXXXX",
    "name": "文件夹名称"
  }
}
```

**注意事项**:
- `folder_token` 为父文件夹 token，可以通过 URL 获取或通过 API 查询
- 创建的文件夹默认只有机器人可见，如需用户可见需要设置权限

---

### 3. 获取文件夹内容

**接口说明**: 获取指定文件夹下的文件和子文件夹列表

**推荐方法 (Explorer v2)**:

```
GET /open-apis/drive/explorer/v2/folder/:folder_token/children
```

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "children": {
      "file_token1": {
        "token": "file_token1",
        "name": "文件名",
        "type": "file"
      },
      "folder_token1": {
        "token": "folder_token1",
        "name": "文件夹名",
        "type": "folder"
      }
    },
    "parentToken": "folder_token"
  },
  "msg": "success"
}
```

**注意事项**:
- `type` 为 `folder` 表示文件夹，为 `file` 表示文件
- v2 版本的 `children` 是字典格式，不是数组

---

### 4. 上传文件

**接口说明**: 上传文件到指定文件夹

```
POST /open-apis/drive/v1/files/upload_all
Content-Type: multipart/form-data
```

**请求参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| file | binary | 是 | 文件二进制内容 |
| file_name | string | 是 | 文件名 |
| parent_type | string | 是 | 父节点类型，`explorer` = 云空间 |
| parent_node | string | 是 | 父节点 token（文件夹 token） |
| size | number | 是 | 文件大小（字节） |

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "file_token": "file_token"
  }
}
```

**注意事项**:
- `parent_type` 使用 `explorer` 表示云空间文件夹
- `size` 参数必填，建议在上传前计算文件大小
- 大文件（超过 10MB）建议使用分片上传接口

---

### 5. 下载文件

**接口说明**: 根据文件 token 下载文件

```
GET /open-apis/drive/v1/files/:file_token/download
```

**请求参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| file_token | string | 是 | 文件 token |

**响应**:
- 返回文件二进制流
- Content-Type 根据文件类型自动设置

**注意事项**:
- 需要在请求头中携带 `Authorization: Bearer {tenant_access_token}`
- 下载的是二进制流，需要正确处理响应体

---

### 6. 获取用户 Open ID

**接口说明**: 通过邮箱或手机号获取用户的 open_id

```
POST /open-apis/contact/v3/users/batch_get_id
```

**请求参数**:
```json
{
  "emails": ["user@example.com"],
  "mobiles": ["13800138000"],
  "include_resigned": false
}
```

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "user_list": [
      {
        "user_id": "ou_xxxxxxxxx",
        "email": "user@example.com",
        "status": {
          "is_activated": true,
          "is_resigned": false
        }
      }
    ]
  }
}
```

**注意事项**:
- 支持批量查询，最多 50 个邮箱或手机号
- 需要 `contact:user.id:readonly` 权限
- 返回的 `user_id` 就是 `open_id`

---

### 7. 添加文件夹权限

**接口说明**: 为文件夹添加用户权限

```
POST /open-apis/drive/v1/permissions/:token/members?type=folder
```

**请求参数**:
```json
{
  "member_type": "openid",
  "member_id": "ou_xxxxxxxxx",
  "perm": "full_access",
  "perm_type": "container",
  "type": "user"
}
```

**权限类型**:
| perm | 说明 |
|------|------|
| `view` | 可阅读 |
| `edit` | 可编辑 |
| `full_access` | 可管理（完全访问） |

**注意事项**:
- 创建文件夹后，默认只有机器人可见
- 必须通过此接口为用户添加权限，用户才能看到文件夹
- `member_id` 必须是 `open_id`，不能是 `user_id`
- **权限问题排查**：如果遇到机器人无法获取所创建文件夹的权限，请参考官方文档 https://open.feishu.cn/document/server-docs/docs/drive-v1/faq#b02e5bfb

---

### 8. 获取文件元数据

**接口说明**: 获取文件的详细信息

```
GET /open-apis/drive/v1/files/:file_token
```

**请求参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| file_token | string | 是 | 文件或文件夹 token |

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "token": "token",
    "name": "名称",
    "type": "file/folder",
    "size": 1024,
    "created_time": 1234567890,
    "owner": {
      "open_id": "xxx"
    }
  }
}
```

---

### 9. 删除文件夹

**接口说明**: 删除指定文件夹（删除后进入回收站）

```
DELETE /open-apis/drive/v1/files/:folder_token?type=folder
```

**请求参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| folder_token | string | 是 | 文件夹 token |
| type | string | 是 | 固定值 `folder` |

**响应示例**:
```json
{
  "code": 0,
  "msg": "success"
}
```

**注意事项**:
- 删除后文件夹会进入回收站，可以在回收站中恢复
- 需要具有文件夹的编辑权限才能删除
- **重要**: 执行删除操作前必须向用户确认，避免误删

**Python 示例**:
```python
# 删除文件夹（带确认提示）
def delete_folder_with_confirm(client, folder_token, folder_name, confirmed=False):
    # 1. 显示文件夹信息
    print(f"即将删除文件夹: {folder_name}")
    print(f"Token: {folder_token}")
    
    # 2. 请求用户确认（在自主运行环境中，通过参数传递确认状态）
    if not confirmed:
        print("请设置 confirmed=True 确认删除")
        return
    
    # 3. 执行删除
    result = client.delete_folder(folder_token)
    if result.get("code") == 0:
        print("删除成功！文件夹已进入回收站")
    else:
        print(f"删除失败: {result.get('msg')}")

# 使用示例 - 必须显式确认
delete_folder_with_confirm(client, "folder_token", "测试文件夹", confirmed=True)
```

---

### 10. 删除文件

**接口说明**: 删除指定文件（删除后进入回收站）

```
DELETE /open-apis/drive/v1/files/:file_token?type=file
```

**请求参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| file_token | string | 是 | 文件 token |
| type | string | 是 | 固定值 `file` |

**注意事项**:
- 删除后文件会进入回收站，可以在回收站中恢复
- 需要具有文件的编辑权限才能删除
- **重要**: 执行删除操作前必须向用户确认

---

### 11. 移动文件或文件夹

**接口说明**: 将文件或文件夹移动到指定文件夹

```
POST /open-apis/drive/v1/files/:file_token/move
```

**请求参数**:
```json
{
  "type": "file",
  "destination_folder_token": "目标文件夹token"
}
```

**类型说明**:
| type 值 | 说明 |
|---------|------|
| `file` | 普通文件 |
| `folder` | 文件夹 |
| `doc` | 文档 |
| `sheet` | 电子表格 |
| `bitable` | 多维表格 |
| `docx` | 新版文档 |

---

### 12. 复制文件

**接口说明**: 复制文件到指定文件夹（异步操作）

```
POST /open-apis/drive/v1/files/:file_token/copy
```

**请求参数**:
```json
{
  "type": "file",
  "destination_folder_token": "目标文件夹token",
  "name": "复制后的新名称(可选)"
}
```

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "ticket": "task_ticket_xxx"
  },
  "msg": "success"
}
```

**注意事项**:
- 复制是异步操作，返回 ticket 用于查询任务状态
- 使用 `check_task_status(ticket)` 查询复制进度

---

### 13. 批量获取文件元数据

**接口说明**: 批量获取多个文件的元数据信息

```
POST /open-apis/drive/v1/metas/batch_query
```

**请求参数**:
```json
{
  "file_tokens": ["token1", "token2", "token3"]
}
```

**限制**: 最多 100 个文件 token

---

### 14. 获取文件统计信息

**接口说明**: 获取文件的阅读、点赞、评论等统计信息

```
POST /open-apis/drive/v1/files/:file_token/statistics
```

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "uv": 100,
    "pv": 200,
    "like_count": 10,
    "comment_count": 5
  }
}
```

---

### 15. 获取文件访问记录

**接口说明**: 获取谁访问了该文件的记录

```
POST /open-apis/drive/v1/files/:file_token/view_records
```

**请求参数**:
```json
{
  "page_size": 50,
  "page_token": "可选的分页token"
}
```

---

### 16. 创建文件快捷方式

**接口说明**: 在指定文件夹创建文件的快捷方式

```
POST /open-apis/drive/v1/files/create_shortcut
```

**请求参数**:
```json
{
  "file_token": "源文件token",
  "folder_token": "目标文件夹token",
  "type": "file"
}
```

---

### 17. 搜索文件

**接口说明**: 在云空间中搜索文件

```
POST /open-apis/suite/docs-api/search/object
```

**请求参数**:
```json
{
  "search_key": "title",
  "search_value": "搜索关键词",
  "page_size": 50
}
```

**search_key 说明**:
| 值 | 说明 |
|----|------|
| `title` | 按标题搜索 |
| `content` | 按内容搜索 |

**注意事项**:
- 此接口需要 `user_access_token`，不支持 `tenant_access_token`

---

### 18. 查询异步任务状态

**接口说明**: 查询复制、移动等异步操作的任务状态

```
GET /open-apis/drive/v1/files/task_check?ticket=xxx
```

**请求参数**:
| 参数 | 类型 | 必填 | 说明 |
|------|------|------|------|
| ticket | string | 是 | 异步任务 ticket |

**响应示例**:
```json
{
  "code": 0,
  "data": {
    "status": "success",
    "file_token": "新文件token"
  }
}
```

**status 说明**:
| 值 | 说明 |
|----|------|
| `pending` | 等待中 |
| `processing` | 处理中 |
| `success` | 成功 |
| `failed` | 失败 |

---

## 错误处理

| 错误码 | 含义 | 解决方案 |
|--------|------|----------|
| 0 | 成功 | — |
| 99991663 | token 过期 | 重新获取 tenant_access_token |
| 1061002 | 无权限 | 检查应用权限和文件夹授权 |
| 1061001 | 文件/文件夹不存在 | 检查 token 是否正确 |
| 1061045 | 文件大小超限 | 使用分片上传或减小文件大小 |
| 404 | 文件不存在 | **常见原因**：使用了字典 key 而非 item['token']，参见下方常见错误 |

---

## ⚠️ 常见错误：Token 混淆导致 404

### 问题描述

在获取文件夹内容后尝试下载文件时，出现 404 错误。

### 根本原因

**混淆了飞书 API 返回数据结构中的两种"token"**：

```json
{
  "children": {
    "nodcn5OkQG6q8Y4SuSncukJmCtc": {  // ← 错误：这是字典的 key，不是下载用 token
      "token": "KdLTbke3BoN85RxQg5qcswFYnah",  // ← 正确：这才是下载用的 token
      "name": "Screenshot_20260323-115306.png",
      "type": "file"
    }
  }
}
```

### 错误写法 ❌

```python
result = client.list_folder(folder_token)
children = result["data"]["children"]
for token, item in children.items():  # ← token 实际是 dict_key (nodcn...)
    file_token = token  # ← 错误！这会导致 404
    client.download_file(file_token, "/path/to/file")
```

### 正确写法 ✅

```python
result = client.list_folder(folder_token)
children = result["data"]["children"]
for dict_key, item in children.items():  # dict_key 是 nodcn...
    file_token = item["token"]  # ← 正确！从 item 中获取 token
    client.download_file(file_token, "/path/to/file")

# 或者直接使用 list_all() 方法，它已经处理了这个问题
files = client.list_all(folder_token)
for file in files:
    client.download_file(file["token"], f"/path/to/{file['name']}")
```

### 记住这个规则

| 位置 | 值 | 用途 |
|------|-----|------|
| 字典 key | `nodcn5OkQG6q8Y4SuSncukJmCtc` | 仅用于迭代，通常不使用 |
| `item['token']` | `KdLTbke3BoN85RxQg5qcswFYnah` | **下载、删除、复制、移动等所有操作** |

---

## 使用建议

### 权限配置

确保应用已获取以下权限：
- `drive:file:read` - 读取文件
- `drive:file:write` - 写入文件
- `drive:folder:read` - 读取文件夹
- `drive:folder:write` - 创建文件夹
- `contact:user.id:readonly` - 获取用户 ID（用于权限管理）

### 最佳实践

1. **最小权限原则**: 为飞书应用仅授予必需的权限，避免过度授权
2. **测试应用**: 建议创建专门的测试应用，使用受限权限进行开发测试
3. **权限管理**: 通过 API 创建的文件默认只有机器人可见，需要注意权限设置
4. **冒烟测试**: 执行任何操作前，先用 `get_file_info` 测试 token 是否可用
5. **分页处理**: 文件列表可能很多，务必处理分页逻辑
6. **错误重试**: 对于网络错误和临时错误，建议实现重试机制

### 安全注意事项

1. **不要在前端代码中暴露 tenant_access_token**
2. **不要分享生产环境的 FEISHU_APP_SECRET**
3. **不要将凭证提交到代码仓库**
2. 定期轮换访问令牌
3. 限制文件上传大小，避免滥用
4. 验证文件类型，防止上传恶意文件