npm package: @gulibs/tegg-ali-oss
Description: OSS (Object Storage Service) plugin for Egg.js - Alibaba Cloud OSS integration powered by ali-oss
Author: HectorGu
Latest version: 0.0.1

# @gulibs/tegg-ali-oss

![NPM version](https://img.shields.io/npm/v/@gulibs/tegg-ali-oss.svg?style=flat-square)

> [English](README.md)

[OSS](https://cn.aliyun.com/product/oss)（对象存储服务）插件，用于 Egg.js - 阿里云 OSS 集成。

## 特性

- ✅ **TypeScript 支持** - 完整的 TypeScript 类型定义，零配置
- ✅ **OSS Client 2.x** - 基于 [oss-client](https://github.com/node-modules/oss-client) 2.x，使用统一的 `OSSObject` API
- ✅ **多 Bucket 支持** - 支持配置多个 OSS bucket
- ✅ **Agent 支持** - 可选择在 agent 进程中初始化
- ✅ **内网访问** - 支持阿里云内网访问，节省带宽成本
- ✅ **自定义域名** - 支持 CNAME 自定义域名配置
- ✅ **请求者付费** - 支持请求者付费模式
- ✅ **日志集成** - 内置日志记录，便于调试和监控

## 要求

- Node.js >= 22.18.0
- Egg.js >= 4.1.0-beta.34

## 安装

### 安装最新版本

```bash
npm i @gulibs/tegg-ali-oss
# 或
npm i @gulibs/tegg-ali-oss@latest
```

### 安装 Beta 版本

要安装 beta 版本，必须显式指定 `@beta` 标签：

```bash
npm i @gulibs/tegg-ali-oss@beta
```

**注意**：使用 `@latest` 或不指定标签将安装最新的稳定版本，而不是 beta 版本。

## 快速开始

### 1. 启用插件

```typescript
// config/plugin.ts
import ossPlugin from '@gulibs/tegg-ali-oss';

export default {
  ...ossPlugin(),
};
```

### 2. 配置 OSS

在 `${baseDir}/config/config.{env}.ts` 中填写必要的配置信息：

```typescript
// config/config.default.ts
export default {
  oss: {
    client: {
      accessKeyId: 'your access key',
      accessKeySecret: 'your access secret',
      bucket: 'your bucket name',
      endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
      // 或使用 region 代替
      region: 'oss-cn-hangzhou',
      timeout: '60s', // 或数字（毫秒）
    },
  },
};
```

### 3. 在代码中使用 OSS

```typescript
import { Controller } from 'egg';

export default class extends Controller {
  async upload() {
    const ctx = this.ctx;

    // 上传文件到 OSS
    const result = await ctx.oss.put('path/to/file.txt', fileContent);
    console.log('上传成功:', result.url);

    // 从 OSS 获取文件
    const file = await ctx.oss.get('path/to/file.txt');

    // 从 OSS 删除文件
    await ctx.oss.delete('path/to/file.txt');
  }
}
```

## 配置说明

### 基础配置

```typescript
export default {
  oss: {
    client: {
      accessKeyId: 'your access key',
      accessKeySecret: 'your access secret',
      bucket: 'your bucket name',
      endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
      timeout: '60s',
    },
  },
};
```

### 使用 Region 代替 Endpoint

```typescript
export default {
  oss: {
    client: {
      accessKeyId: 'your access key',
      accessKeySecret: 'your access secret',
      bucket: 'your bucket name',
      region: 'oss-cn-hangzhou', // endpoint 会自动生成
      timeout: '60s',
    },
  },
};
```

### 内网访问

如果您的应用运行在阿里云上，可以使用内网访问以节省带宽成本：

```typescript
export default {
  oss: {
    client: {
      accessKeyId: 'your access key',
      accessKeySecret: 'your access secret',
      bucket: 'your bucket name',
      endpoint: 'oss-cn-hangzhou-internal.aliyuncs.com',
      internal: true, // 使用内网
    },
  },
};
```

### 自定义域名（CNAME）

```typescript
export default {
  oss: {
    client: {
      accessKeyId: 'your access key',
      accessKeySecret: 'your access secret',
      bucket: 'your bucket name',
      endpoint: 'https://my-static.domain.com',
      cname: true, // 启用 CNAME
    },
  },
};
```

### 请求者付费模式

```typescript
export default {
  oss: {
    client: {
      accessKeyId: 'your access key',
      accessKeySecret: 'your access secret',
      bucket: 'your bucket name',
      endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
      isRequestPay: true, // 启用请求者付费
    },
  },
};
```

### 在 Agent 中初始化

默认情况下，OSS 在应用进程中初始化。要在 agent 进程中初始化：

```typescript
export default {
  oss: {
    useAgent: true,
    client: {
      // ... OSS 配置
    },
  },
};
```

## 多 Bucket 配置

如果您的应用需要访问多个 OSS bucket：

### 1. 配置多个客户端

```typescript
// config/config.default.ts
export default {
  oss: {
    clients: {
      bucket1: {
        bucket: 'bucket1',
        endpoint: 'https://oss-cn-hangzhou.aliyuncs.com',
        accessKeyId: 'your access key',
        accessKeySecret: 'your access secret',
      },
      bucket2: {
        bucket: 'bucket2',
        endpoint: 'https://oss-cn-beijing.aliyuncs.com',
        accessKeyId: 'your access key',
        accessKeySecret: 'your access secret',
      },
    },
    // 所有客户端共享的默认配置
    default: {
      timeout: '60s',
    },
  },
};
```

### 2. 使用多个客户端

```typescript
// app.ts 或 controller
import type { Application } from 'egg';

export default (app: Application) => {
  // 获取已配置的客户端
  const bucket1 = app.oss.get('bucket1');
  const bucket2 = app.oss.get('bucket2');

  // 动态创建新实例
  const bucket3 = app.oss.createInstance({
    bucket: 'bucket3',
    endpoint: 'https://oss-cn-shanghai.aliyuncs.com',
    accessKeyId: 'your access key',
    accessKeySecret: 'your access secret',
  });
};
```

## 使用示例

### 上传文件

```typescript
import path from 'node:path';
import fs from 'node:fs/promises';
import { Controller } from 'egg';

export default class extends Controller {
  async upload() {
    const ctx = this.ctx;
    const file = ctx.request.files[0];
    const name = 'uploads/' + path.basename(file.filename);

    let result;
    try {
      // 上传文件到 OSS
      result = await ctx.oss.put(name, file.filepath);
    } finally {
      // 清理临时文件
      await fs.unlink(file.filepath);
    }

    if (result) {
      ctx.body = {
        url: result.url,
        name: result.name,
      };
    }
  }
}
```

### 下载文件

```typescript
export default class extends Controller {
  async download() {
    const ctx = this.ctx;
    const filename = ctx.params.filename;

    // 获取文件流
    const result = await ctx.oss.getStream(filename);
    ctx.set('Content-Type', result.res.headers['content-type']);
    ctx.set('Content-Disposition', `attachment; filename="${filename}"`);
    ctx.body = result.stream;
  }
}
```

### 列出文件

```typescript
export default class extends Controller {
  async list() {
    const ctx = this.ctx;
    const prefix = ctx.query.prefix || '';

    // 列出指定前缀的对象
    const result = await ctx.oss.list({
      prefix,
      'max-keys': 100,
    });

    ctx.body = {
      objects: result.objects,
      prefixes: result.prefixes,
    };
  }
}
```

### 删除文件

```typescript
export default class extends Controller {
  async delete() {
    const ctx = this.ctx;
    const filename = ctx.params.filename;

    // 从 OSS 删除文件
    await ctx.oss.delete(filename);

    ctx.body = { success: true };
  }
}
```

## API 参考

OSS 客户端实例提供了 [oss-client](https://github.com/node-modules/oss-client) 的所有方法。常用方法包括：

- `put(name, file, options)` - 上传文件
- `get(name, options)` - 获取文件
- `getStream(name, options)` - 获取文件流
- `delete(name, options)` - 删除文件
- `list(options)` - 列出对象
- `head(name, options)` - 获取对象元信息
- `copy(name, sourceName, options)` - 复制对象
- `multipartUpload(name, file, options)` - 分片上传

完整的 API 文档，请参考 [oss-client 文档](https://github.com/node-modules/oss-client)。

## 从 oss-client 1.x 迁移

如果您正在从使用 `oss-client` 1.x 的旧版本迁移，请注意以下变化：

1. **统一 API**：所有客户端现在使用 `OSSObject` 类，而不是单独的 `Client`、`STS` 和 `ClusterClient`
2. **移除的功能**：不再支持 `cluster` 和 `sts` 配置选项
3. **新增选项**：添加了对 `internal`、`isRequestPay` 和 `cname` 选项的支持

## 日志

插件提供内置日志记录，便于调试和监控：

- 插件初始化日志
- OSS 客户端创建日志
- 配置信息（不包含敏感数据）

日志前缀为 `[tegg-ali-oss]`，便于过滤。

## 许可证

[MIT](LICENSE)