mirror of
https://github.com/labring/FastGPT.git
synced 2026-05-05 01:02:59 +08:00
c93c3937e1
* refactor: fastgpt object storage & global proxy (#6155) * feat: migrate to fastgpt storage sdk * chore: rename env variable * chore: move to sdk dir * docs: object storage * CHORE * chore: storage mocks * chore: update docker-compose * fix: global proxy agent * fix: update COS proxy * refactor: use fetch instead of http.request * fix: axios request base url * fix: axios proxy request behavior * fix: bumps axios * fix: patch axios for proxy * fix: replace axios with proxied axios * fix: upload txt file encoding * clean code * fix: use "minio" for minio adapter (#6205) * fix: use minio client to delete files when using minio vendor (#6206) * doc * feat: filter citations and add response button control (#6170) * feat: filter citations and add response button control * i18n * fix * fix test * perf: chat api code * fix: workflow edge overlap and auto-align in folded loop nodes (#6204) * fix: workflow edge overlap and auto-align in folded loop nodes * sort * fix * fix edge * fix icon * perf: s3 file name * perf: admin get app api * perf: catch user error * fix: refactor useOrg hook to use debounced search key (#6180) * chore: comment minio adapter (#6207) * chore: filename with suffix random id * perf: s3 storage code * fix: encode filename when copy object --------- Co-authored-by: archer <545436317@qq.com> * fix: node card link * json * perf: chat index; * index * chat item soft delete (#6216) * chat item soft delete * temp * fix * remove code * perf: delete chat item --------- Co-authored-by: archer <545436317@qq.com> * feat: select wheather filter sensitive info when export apps (#6222) * fix some bugs (#6210) * fix v4.14.5 bugs * type * fix * fix * custom feedback * fix * code * fix * remove invalid function --------- Co-authored-by: archer <545436317@qq.com> * perf: test * fix file default local upload (#6223) * docs: improve object storage introduction (#6224) * doc --------- Co-authored-by: roy <whoeverimf5@gmail.com> Co-authored-by: heheer <heheer@sealos.io> Co-authored-by: Finley Ge <32237950+FinleyGe@users.noreply.github.com>
201 lines
6.3 KiB
Markdown
201 lines
6.3 KiB
Markdown
# @fastgpt-sdk/storage
|
||
|
||
FastGPT 的对象存储 SDK,提供 **统一的、与厂商无关的**存储接口(S3/MinIO/OSS/COS 等),用于上传、下载、删除、列举对象以及获取元数据。
|
||
|
||
> 本包为 ESM(`"type": "module"`),并要求 Node.js **>= 20**。
|
||
|
||
## 安装
|
||
|
||
```bash
|
||
pnpm add @fastgpt-sdk/storage
|
||
```
|
||
|
||
## 快速开始
|
||
|
||
```ts
|
||
import { createStorage } from '@fastgpt-sdk/storage';
|
||
import { createWriteStream } from 'node:fs';
|
||
|
||
const storage = createStorage({
|
||
vendor: 'minio',
|
||
bucket: 'my-bucket',
|
||
region: 'us-east-1',
|
||
endpoint: 'http://127.0.0.1:9000',
|
||
credentials: {
|
||
accessKeyId: process.env.MINIO_ACCESS_KEY ?? '',
|
||
secretAccessKey: process.env.MINIO_SECRET_KEY ?? ''
|
||
},
|
||
// minio 常见配置:若你的服务不支持 virtual-host 访问方式,可打开它
|
||
forcePathStyle: true
|
||
});
|
||
|
||
// 1) 确保 bucket 存在(不存在则尝试创建)
|
||
await storage.ensureBucket();
|
||
|
||
// 2) 上传
|
||
await storage.uploadObject({
|
||
key: 'demo/hello.txt',
|
||
body: 'hello fastgpt',
|
||
contentType: 'text/plain; charset=utf-8',
|
||
metadata: {
|
||
app: 'fastgpt',
|
||
purpose: 'readme-demo'
|
||
}
|
||
});
|
||
|
||
// 3) 下载(流式)
|
||
const { body } = await storage.downloadObject({ key: 'demo/hello.txt' });
|
||
body.pipe(createWriteStream('/tmp/hello.txt'));
|
||
|
||
// 4) 删除
|
||
await storage.deleteObject({ key: 'demo/hello.txt' });
|
||
|
||
// 5) 释放资源(部分 adapter 可能是空实现)
|
||
await storage.destroy();
|
||
```
|
||
|
||
## 配置(IStorageOptions)
|
||
|
||
通过 `vendor` 字段选择适配器(判别联合),不同厂商的配置项在 `IStorageOptions` 上有清晰的类型约束与中文 JSDoc。
|
||
|
||
### AWS S3
|
||
|
||
```ts
|
||
import { createStorage } from '@fastgpt-sdk/storage';
|
||
|
||
const storage = createStorage({
|
||
vendor: 'aws-s3',
|
||
bucket: 'my-bucket',
|
||
region: 'ap-northeast-1',
|
||
credentials: {
|
||
accessKeyId: process.env.AWS_ACCESS_KEY_ID ?? '',
|
||
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? ''
|
||
}
|
||
});
|
||
```
|
||
|
||
### MinIO / 其他 S3 兼容
|
||
|
||
```ts
|
||
import { createStorage } from '@fastgpt-sdk/storage';
|
||
|
||
const storage = createStorage({
|
||
vendor: 'minio',
|
||
bucket: 'my-bucket',
|
||
region: 'us-east-1',
|
||
endpoint: 'http://127.0.0.1:9000',
|
||
credentials: {
|
||
accessKeyId: process.env.MINIO_ACCESS_KEY ?? '',
|
||
secretAccessKey: process.env.MINIO_SECRET_KEY ?? ''
|
||
},
|
||
forcePathStyle: true
|
||
});
|
||
```
|
||
|
||
### 阿里云 OSS
|
||
|
||
```ts
|
||
import { createStorage } from '@fastgpt-sdk/storage';
|
||
|
||
const storage = createStorage({
|
||
vendor: 'oss',
|
||
bucket: 'my-bucket',
|
||
region: 'oss-cn-hangzhou',
|
||
endpoint: process.env.OSS_ENDPOINT, // 视你的部署与 SDK 配置而定
|
||
credentials: {
|
||
accessKeyId: process.env.OSS_ACCESS_KEY_ID ?? '',
|
||
secretAccessKey: process.env.OSS_ACCESS_KEY_SECRET ?? ''
|
||
},
|
||
cname: false,
|
||
internal: false
|
||
});
|
||
```
|
||
|
||
### 腾讯云 COS
|
||
|
||
```ts
|
||
import { createStorage } from '@fastgpt-sdk/storage';
|
||
|
||
const storage = createStorage({
|
||
vendor: 'cos',
|
||
bucket: 'my-bucket',
|
||
region: 'ap-guangzhou',
|
||
credentials: {
|
||
accessKeyId: process.env.COS_SECRET_ID ?? '',
|
||
secretAccessKey: process.env.COS_SECRET_KEY ?? ''
|
||
},
|
||
protocol: 'https:',
|
||
useAccelerate: false
|
||
});
|
||
```
|
||
|
||
## API(IStorage)
|
||
|
||
`createStorage(options)` 返回一个实现了 `IStorage` 的实例:
|
||
|
||
- **`ensureBucket()`**: 确保 bucket 存在(不存在时**可能**尝试创建,取决于 vendor 与权限;部分厂商仅做存在性校验并直接抛错)。
|
||
- **`checkObjectExists({ key })`**: 判断对象是否存在。
|
||
- **`uploadObject({ key, body, contentType?, contentLength?, contentDisposition?, metadata? })`**: 上传对象。
|
||
- **`downloadObject({ key })`**: 下载对象(返回 `Readable`)。
|
||
- **`deleteObject({ key })`**: 删除单个对象。
|
||
- **`deleteObjectsByMultiKeys({ keys })`**: 按 key 列表批量删除(返回失败 key 列表)。
|
||
- **`deleteObjectsByPrefix({ prefix })`**: 按前缀批量删除(高危,务必使用非空 prefix;返回失败 key 列表)。
|
||
- **`generatePresignedPutUrl({ key, expiredSeconds?, metadata? })`**: 生成 **PUT** 预签名 URL(用于前端直传)。
|
||
- **`generatePresignedGetUrl({ key, expiredSeconds? })`**: 生成 **GET** 预签名 URL(用于临时授权下载)。
|
||
- **`listObjects({ prefix? })`**: 列出对象 key(可按前缀过滤;不传则列出整个 bucket 内对象)。
|
||
- **`getObjectMetadata({ key })`**: 获取对象元数据。
|
||
- **`destroy()`**: 资源清理/连接释放。
|
||
|
||
> 重要:当前实现状态(以代码为准):
|
||
> - `generatePresignedPutUrl`:**AWS S3 / MinIO / COS / OSS 已实现**。
|
||
> - `generatePresignedGetUrl`:目前各 adapter 仍为 **未实现**(会抛 `Error('Method not implemented.')`)。
|
||
|
||
### 预签名 PUT 直传示例(浏览器 / 前端)
|
||
|
||
`generatePresignedPutUrl` 返回的 `metadata` 字段语义更接近“需要带上的 headers”(不同厂商前缀不同,如 `x-oss-meta-*` / `x-cos-meta-*`)。
|
||
|
||
```ts
|
||
const { putUrl, metadata } = await storage.generatePresignedPutUrl({
|
||
key: 'demo/hello.txt',
|
||
expiredSeconds: 600,
|
||
metadata: { app: 'fastgpt', purpose: 'direct-upload' }
|
||
});
|
||
|
||
await fetch(putUrl, {
|
||
method: 'PUT',
|
||
headers: {
|
||
// 将 adapter 返回的 headers 带上(若为空对象也没关系)
|
||
...metadata,
|
||
'content-type': 'text/plain; charset=utf-8'
|
||
},
|
||
body: 'hello fastgpt'
|
||
});
|
||
```
|
||
|
||
## 错误与异常
|
||
|
||
导出的错误类型:
|
||
|
||
- **`NoSuchBucketError`**: bucket 不存在(部分 adapter 会用它包装底层错误)。
|
||
- **`NoBucketReadPermissionError`**: bucket 无读取权限(部分 adapter 会用它包装底层错误)。
|
||
- **`EmptyObjectError`**: 下载时对象为空(例如底层 SDK 返回 `Body` 为空)。
|
||
|
||
建议你在业务层做分层处理:可恢复错误(重试/提示权限)与不可恢复错误(配置错误/接口未实现)。
|
||
|
||
## 注意事项
|
||
|
||
- **按前缀删除是高危操作**:`prefix` 必须是非空字符串;强烈建议使用业务隔离前缀(例如 `team/{teamId}/`),避免误删整桶。
|
||
- **metadata 厂商差异**:不同厂商对元数据 key 前缀/大小写/可用字符/大小限制不同,建议使用简单 ASCII key,并控制总体大小。
|
||
- **流式下载/上传**:大文件建议使用 `Readable`,减少内存峰值。
|
||
|
||
## 开发与构建
|
||
|
||
```bash
|
||
pnpm -C FastGPT/packages/storage dev
|
||
pnpm -C FastGPT/packages/storage build
|
||
```
|
||
|
||
发布前会执行 `prepublishOnly` 自动构建产物到 `dist/`。
|
||
|
||
|