object-storage-js
Version:
Object storage SDK for browser — supports server upload, MinIO, OBS, OSS, AWS S3, Qiniu Kodo, and Baidu BOS
280 lines (224 loc) • 10.5 kB
Markdown
# object-storage-js
面向浏览器端上传场景的对象存储适配层。它把服务端上传、主流云厂商 SDK 上传和 S3 协议上传统一到同一套初始化、上传、进度和取消接口中,业务代码只需要切换 `type` 和配置即可。
## 能力概览
- **统一接口**:所有 Provider 通过 `new ObjectStorage(config).upload(params)` 调用。
- **按需引入 SDK**:不内置云厂商 SDK,由业务方通过 `sdkObject` 传入,避免增加基础包体积。
- **上传进度**:统一输出 `{ loaded, total, percent }`。
- **取消上传**:通过 `onCancel` 暴露取消句柄;支持能力取决于底层 SDK 或 XHR。
- **大文件处理**:normal、OSS、OBS、S3/MinIO、七牛云、百度 BOS 等场景按各自 SDK 能力支持分片或并发参数。
- **扩展友好**:内部采用 Adapter 结构,新增 Provider 只需要增加对应上传实现和配置类型。
## 支持的 Provider
| Type | Provider | SDK / 上传方式 | 说明 |
| -------- | --------- | ------------------ | ----------------------------- |
| `normal` | 业务服务端 | XHR + FormData | 适合上传到自有后端,再由后端落对象存储。 |
| `oss` | 阿里云 OSS | `ali-oss` | 支持 AK/SK、STS、multipartUpload。 |
| `obs` | 华为云 OBS | OBS Browser SDK | 小文件走预签名 PUT,大文件走 SDK 分片上传。 |
| `minio` | MinIO | AWS SDK v2 S3 | S3 兼容协议,默认开启 path style。 |
| `aws` | AWS S3 | AWS SDK v2 S3 | 兼容 AWS SDK v2 的 S3 上传能力。 |
| `qiniu` | 七牛云 Kodo | 七牛云 JS SDK | 使用业务服务端签发的 uploadToken 上传。 |
| `bos` | 百度智能云 BOS | 百度 BOS Browser SDK | 支持 AK/SK、服务端签名和分块上传。 |
## 安装
```bash
pnpm add object-storage-js
```
## 快速开始
```ts
import ObjectStorage, { ObjectStorageType } from 'object-storage-js';
const storage = new ObjectStorage({
type: ObjectStorageType.OSS,
sdkObject: OSS,
accessKey: 'your-access-key',
secretKey: 'your-secret-key',
securityToken: 'optional-sts-token',
bucketName: 'example-bucket',
endPoint: 'https://oss-cn-hangzhou.aliyuncs.com',
});
await storage.upload({
file,
fileName: `uploads/${file.name}`,
maxSize: 100 * 1024 * 1024,
partSize: 5 * 1024 * 1024,
queueLength: 3,
onUploadProgress(progress) {
console.log(progress.percent);
},
onCancel(handle) {
// handle.cancel();
},
});
```
## UMD 用法
适合直接在浏览器中通过 `<script>` 标签引入。UMD 构建会暴露全局变量 `ObjectStorage`,其中包含默认导出的构造函数、命名导出的 `ObjectStorage` 和 `ObjectStorageType`。
```html
<input id="file" type="file" />
<script src="https://unpkg.com/object-storage-js/dist/index.umd.js"></script>
<script>
const { ObjectStorage: StorageClient, ObjectStorageType } = window.ObjectStorage;
document.querySelector('#file').addEventListener('change', async (event) => {
const file = event.target.files[0];
if (!file) return;
const storage = new StorageClient({
type: ObjectStorageType.NORMAL,
});
await storage.upload({
file,
fileName: file.name,
uploadUrl: '/api/files/upload',
mergeUrl: '/api/files/merge',
maxSize: 100 * 1024 * 1024,
onUploadProgress(progress) {
console.log(`upload progress: ${progress.percent}%`);
},
});
});
</script>
```
## API
### `new ObjectStorage(config)`
公共配置字段:
| 字段 | 类型 | 说明 |
| ---------------- | ------------------------- | ----------------------------- |
| `type` | `ObjectStorageType` | Provider 类型。 |
| `sdkObject` | `unknown` | 云厂商 SDK 构造函数或模块;`normal` 不需要。 |
| `sdkOtherParams` | `Record<string, unknown>` | 透传给 SDK 构造函数的额外参数。 |
Provider 配置字段:
| Provider | 必填字段 | 可选字段 |
| --------------- | ------------------------------------- | --------------------------------------------------------------------------------- |
| `normal` | 无 | 无 |
| `oss` | `sdkObject`, `bucketName`, `endPoint` | `accessKey`, `secretKey`, `securityToken`, `region`, `sdkOtherParams` |
| `obs` | `sdkObject`, `bucketName`, `endPoint` | `accessKey`, `secretKey`, `securityToken`, `sdkOtherParams` |
| `minio` / `aws` | `sdkObject`, `bucketName` | `accessKey`, `secretKey`, `securityToken`, `endPoint`, `region`, `sdkOtherParams` |
| `qiniu` | `sdkObject` | `uploadToken`, `sdkOtherParams` |
| `bos` | `sdkObject`, `bucketName`, `endPoint` | `accessKey`, `secretKey`, `signatureUrl`, `sdkOtherParams` |
### `upload(params)`
| 字段 | 类型 | 说明 |
| ------------------ | ------------------------- | ----------------------------------- |
| `file` | `File` | 要上传的文件。 |
| `fileName` | `string` | 目标对象 key;不传时使用 `file.name`。 |
| `maxSize` | `number` | 超过该大小后启用分片/大文件策略,具体行为由 Provider 决定。 |
| `partSize` | `number` | 分片大小,单位字节。 |
| `queueLength` | `number` | 分片上传并发数。 |
| `uploadUrl` | `string` | `normal` 上传接口地址。 |
| `mergeUrl` | `string` | `normal` 分片合并接口地址。 |
| `uploadToken` | `string` | 上传凭证,例如七牛云 token;会覆盖初始化配置里的 token。 |
| `contentType` | `string` | 显式指定内容类型。 |
| `sdkUploadParams` | `Record<string, unknown>` | 透传给厂商上传方法的额外参数。 |
| `onUploadProgress` | `(progress) => void` | 上传进度回调。 |
| `onCancel` | `(handle) => void` | 上传可取消时回调取消句柄。 |
## Provider 示例
### normal:上传到业务服务端
```ts
const storage = new ObjectStorage({
type: ObjectStorageType.NORMAL,
});
await storage.upload({
file,
uploadUrl: '/api/files/upload',
mergeUrl: '/api/files/merge',
maxSize: 100 * 1024 * 1024,
});
```
`normal` 分片上传会向 `uploadUrl` 提交 `file`、`uploadId`、`chunk`、`chunks`、`fileName`,最后请求 `mergeUrl?uploadId=xxx&fileName=xxx`。
### 阿里云 OSS
```ts
import OSS from 'ali-oss';
import ObjectStorage, { ObjectStorageType } from 'object-storage-js';
const storage = new ObjectStorage({
type: ObjectStorageType.OSS,
sdkObject: OSS,
bucketName: 'example-bucket',
endPoint: 'https://oss-cn-hangzhou.aliyuncs.com',
region: 'oss-cn-hangzhou',
accessKey: 'your-sts-access-key-id',
secretKey: 'your-sts-access-key-secret',
securityToken: 'your-sts-token',
});
await storage.upload({
file,
fileName: `uploads/${file.name}`,
maxSize: 100 * 1024 * 1024,
partSize: 5 * 1024 * 1024,
queueLength: 3,
onUploadProgress: console.log,
});
```
OSS 浏览器端建议使用服务端签发的 STS 临时凭证,不建议把长期 AccessKey / SecretKey 写入前端代码。
### 华为云 OBS
```ts
import ObsClient from 'esdk-obs-browserjs';
import ObjectStorage, { ObjectStorageType } from 'object-storage-js';
const storage = new ObjectStorage({
type: ObjectStorageType.OBS,
sdkObject: ObsClient,
bucketName: 'example-bucket',
endPoint: 'https://obs.cn-north-4.myhuaweicloud.com',
accessKey: 'your-temporary-access-key-id',
secretKey: 'your-temporary-secret-access-key',
securityToken: 'your-security-token',
});
await storage.upload({
file,
fileName: `uploads/${file.name}`,
maxSize: 100 * 1024 * 1024,
partSize: 5 * 1024 * 1024,
queueLength: 3,
onUploadProgress: console.log,
});
```
OBS 小文件会通过 SDK 生成预签名 URL 后 PUT 上传,大文件会调用 OBS SDK 的 `uploadFile` 分片上传。
### MinIO / AWS S3
```ts
import AWS from 'aws-sdk';
import ObjectStorage, { ObjectStorageType } from 'object-storage-js';
const minioStorage = new ObjectStorage({
type: ObjectStorageType.MINIO,
sdkObject: AWS,
bucketName: 'example-bucket',
endPoint: 'https://minio.example.com',
region: 'us-east-1',
accessKey: 'your-access-key',
secretKey: 'your-secret-key',
});
await minioStorage.upload({
file,
fileName: `uploads/${file.name}`,
maxSize: 100 * 1024 * 1024,
partSize: 5 * 1024 * 1024,
queueLength: 3,
onUploadProgress: console.log,
});
```
AWS S3 使用方式一致,只需要把 `type` 改为 `ObjectStorageType.AWS`,并按实际服务配置 `region`、`endPoint` 和临时凭证。`minio` 会默认开启 S3 path style。
### 七牛云 Kodo
```ts
import * as qiniu from 'qiniu-js';
import ObjectStorage, { ObjectStorageType } from 'object-storage-js';
const storage = new ObjectStorage({
type: ObjectStorageType.QINIU,
sdkObject: qiniu,
uploadToken,
});
await storage.upload({
file,
fileName: `uploads/${file.name}`,
onUploadProgress: console.log,
});
```
七牛云上传 token 应由服务端签发。浏览器端不应该持有 AccessKey / SecretKey。
### 百度 BOS
```ts
import baidubce from '@baiducloud/sdk';
import ObjectStorage, { ObjectStorageType } from 'object-storage-js';
const storage = new ObjectStorage({
type: ObjectStorageType.BOS,
sdkObject: baidubce.sdk,
bucketName: 'example-bucket',
endPoint: 'https://bj.bcebos.com',
signatureUrl: '/api/bos/signature',
});
await storage.upload({
file,
fileName: `uploads/${file.name}`,
contentType: file.type,
});
```