使用 Node.js V2

IBM Cloud® Object Storage ( SDK for Node.js v2 )提供了多项功能,可帮助您充分利用 IBM Cloud Object Storage。

IBM Cloud Object Storage ( SDK for Node.js v2 )功能全面,其众多特性与功能已超出本指南的范围和篇幅。 有关类和方法的详细文档,请参阅 Node.js 的 API 参考文档。 在 GitHub 存储库中可以找到源代码。

新功能 v2

IBM Cloud Object Storage ( SDK for Node.js v2 )是基于 AWS SDK( v3 )架构构建的现代化版本,带来了显著的改进:

  • 模块化架构 ——仅导入您需要的命令和客户端
  • 承诺优先设计 ——原生支持 async/await,并具备更简洁的错误处理机制
  • 更小的打包体积 ——支持树形抖动(Tree-shaking)的模块可缩减应用程序大小
  • 现代版 JavaScript ——利用 ES6+ 的功能并支持 TypeScript
  • 中间件堆栈 ——可扩展的请求/响应管道
  • 更完善的错误处理 ——带有详细信息的结构化错误类型

对于从 v1 迁移过来的开发者,请参阅《 迁移指南 》。

获取 SDK

安装 IBM COS SDK for Node.js 的首选方法是使用 Node.js 的 npm 包管理器。只需在终端窗口中输入以下命令即可:

npm install ibm-cos-sdk-v2

先决条件

  • Node.js 18 或更高版本 ——该 SDK 要求至少使用 Node.js 18 或更高版本。
  • 一个 IBM Cloud Object Storage
  • 来自 IBM Cloud Identity and Access Management 且至少具有 Writer 权限的API密钥
  • 您正在使用的 COS 实例的 ID
  • 令牌获取端点
  • 服务端点

这些值可在 IBM Cloud 控制台中通过 生成“服务凭证” 找到。

导入包

安装 SDK 后,您需要将所需的包导入到 Node.js 应用程序中,才能使用该 SDK,如下例所示:

CommonJS:

const { S3Client } = require('ibm-cos-sdk-v2');
const {
  CreateBucketCommand,
  ListBucketsCommand,
  PutObjectCommand,
  GetObjectCommand
} = require('ibm-cos-sdk-v2');

ES 模块 / TypeScript:

import { S3Client } from 'ibm-cos-sdk-v2';
import {
  CreateBucketCommand,
  ListBucketsCommand,
  PutObjectCommand,
  GetObjectCommand
} from 'ibm-cos-sdk-v2';

SDK 参考资料

核心类

  • S3Client- 用于交互的主要客户端 IBM Cloud Object Storage
  • 命令类 ——每个操作都有一个对应的命令类(例如:PutObjectCommandGetObjectCommand

配置

  • S3Client 构造函数- 根据配置选项创建一个新的 S3 客户端
  • region- 设置客户端的区域
  • endpoint- 设置服务端点 URL
  • 凭据- 设置身份验证凭据

创建客户端并获取服务凭据

为了连接到 IBM Cloud Object Storage,将通过提供凭证信息(API 密钥和服务实例标识)来创建和配置客户机。 这些值还可以自动从凭证文件或环境变量中获取。

通过创建服务凭证或通过 CLI 可以找到凭证。

使用 IBM 进行 IAM 身份验证

以下示例演示了如何使用 IBM 的IAM身份验证和API密钥创建客户端:

CommonJS:

const { S3Client } = require('ibm-cos-sdk-v2');
// Initialize client
const client = new S3Client({
  endpoint: 'https://s3.us-south.cloud-object-storage.appdomain.cloud',
  region: 'us-south',
  credentials: {
    apiKey: '<API_KEY>',
    serviceInstanceId: '<SERVICE_INSTANCE_ID>'
  }
});

TypeScript:

import { S3Client } from 'ibm-cos-sdk-v2';
const client = new S3Client({
  endpoint: 'https://s3.us-south.cloud-object-storage.appdomain.cloud',
  region: 'us-south',
  credentials: {
    apiKey: '<API_KEY>',
    serviceInstanceId: '<SERVICE_INSTANCE_ID>'
  }
});

所需的配置选项包括:

  • endpoint- 您所用 COS 存储桶所在区域的端点 URL
  • region- 您的存储桶所在的区域
  • credentials.apiKey- 具有相应权限的 IBM Cloud API密钥
  • credentials.serviceInstanceId- 您的 COS 实例的 CRN(云资源名称)

代码示例

以下示例假设您已经按照上一节中的说明创建了一个客户端。

创建存储区

const { CreateBucketCommand } = require('ibm-cos-sdk-v2');
const command = new CreateBucketCommand({
  Bucket: 'my-new-bucket',
  CreateBucketConfiguration: {
    LocationConstraint: 'us-south-standard'
  }
});
try {
  const response = await client.send(command);
  console.log('Bucket created successfully');
} catch (err) {
  console.error('Error creating bucket:', err);
}

列出可用的存储桶

const { ListBucketsCommand } = require('ibm-cos-sdk-v2');
try {
  const command = new ListBucketsCommand({});
  const response = await client.send(command);
  console.log('Buckets:');
  if (response.Buckets && response.Buckets.length > 0) {
    response.Buckets.forEach(bucket => {
      console.log(` - ${bucket.Name} (created: ${bucket.CreationDate})`);
    });
  } else {
    console.log(' No buckets found');
  }
} catch (err) {
  console.error('Failed to list buckets:', err);
}

列出包含详细信息的分类

IBM Cloud Object Storage 提供了一项扩展的列出操作,该操作会返回额外的存储桶信息:

const { ListBucketsExtendedCommand } = require('ibm-cos-sdk-v2');
const command = new ListBucketsExtendedCommand({
  IBMServiceInstanceId: '<SERVICE_INSTANCE_ID>',
  Prefix: 'my-bucket-prefix',
  MaxKeys: 100
});
try {
  const response = await client.send(command);
  console.log('Extended Bucket Information:');
  if (response.Buckets && response.Buckets.length > 0) {
    response.Buckets.forEach(bucket => {
      console.log(` Bucket: ${bucket.Name}`);
      console.log(` Location: ${bucket.LocationConstraint}`);
      console.log(` Created: ${bucket.CreationDate}`);
    });
  } else {
    console.log(' No buckets found');
  }
} catch (err) {
  console.error('Failed to list buckets:', err);
}

获取桶的位置

const { GetBucketLocationCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const command = new GetBucketLocationCommand({
  Bucket: bucketName
});
try {
  const response = await client.send(command);
  console.log(`Bucket '${bucketName}' is located in: ${response.LocationConstraint}`);
} catch (err) {
  console.error('Failed to get bucket location:', err);
}

删除存储区

const { DeleteBucketCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket-to-delete';
const command = new DeleteBucketCommand({
  Bucket: bucketName
});
try {
  await client.send(command);
  console.log(`Bucket '${bucketName}' deleted successfully`);
} catch (err) {
  console.error('Failed to delete bucket:', err);
}

注意:必须先清空存储桶,才能将其删除。

将对象上传到存储桶

const { PutObjectCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const objectKey = 'my-object.txt';
const content = 'Hello, IBM Cloud Object Storage!';
const command = new PutObjectCommand({
  Bucket: bucketName,
  Key: objectKey,
  Body: content
});
try {
  const response = await client.send(command);
  console.log(`Object '${objectKey}' uploaded successfully`);
  console.log(`ETag: ${response.ETag}`);
} catch (err) {
  console.error('Failed to upload object:', err);
}

从存储桶中下载对象

const { GetObjectCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const objectKey = 'my-object.txt';
const command = new GetObjectCommand({
  Bucket: bucketName,
  Key: objectKey
});
try {
  const response = await client.send(command);
  // Convert stream to buffer
  const chunks = [];
  for await (const chunk of response.Body) {
    chunks.push(chunk);
  }
  const buffer = Buffer.concat(chunks);
  console.log(`Object '${objectKey}' downloaded successfully`);
  console.log(`Content-Type: ${response.ContentType}`);
  console.log(`Content-Length: ${response.ContentLength} bytes`);
  console.log(`Size: ${buffer.length} bytes`);
} catch (err) {
  console.error('Failed to download object:', err);
}

列出存储桶中的对象

const { ListObjectsV2Command } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const command = new ListObjectsV2Command({
  Bucket: bucketName,
  MaxKeys: 1000
});
try {
  const response = await client.send(command);
  console.log(`Objects in bucket '${bucketName}':`);
  if (response.Contents && response.Contents.length > 0) {
    response.Contents.forEach(object => {
      console.log(` - ${object.Key} (size: ${object.Size} bytes, modified: ${object.LastModified})`);
    });
    console.log(`\nTotal objects: ${response.Contents.length}`);
  } else {
    console.log(' No objects found');
  }
} catch (err) {
  console.error('Failed to list objects:', err);
}

复制对象

const { CopyObjectCommand } = require('ibm-cos-sdk-v2');
const sourceBucket = 'source-bucket';
const sourceKey = 'source-object.txt';
const destinationBucket = 'destination-bucket';
const destinationKey = 'destination-object.txt';
// CopySource format: source-bucket/source-key
const copySource = `${sourceBucket}/${sourceKey}`;
const command = new CopyObjectCommand({
  Bucket: destinationBucket,
  Key: destinationKey,
  CopySource: copySource
});
try {
  const response = await client.send(command);
  console.log('Object copied successfully');
  if (response.CopyObjectResult) {
    console.log(`ETag: ${response.CopyObjectResult.ETag}`);
  }
} catch (err) {
  console.error('Failed to copy object:', err);
}

删除对象

const { DeleteObjectCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const objectKey = 'object-to-delete.txt';
const command = new DeleteObjectCommand({
  Bucket: bucketName,
  Key: objectKey
});
try {
  await client.send(command);
  console.log(`Object '${objectKey}' deleted successfully`);
} catch (err) {
  console.error('Failed to delete object:', err);
}

删除多个对象

const { DeleteObjectsCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const objectsToDelete = [
  'object1.txt',
  'object2.txt',
  'object3.txt'
];
// Build delete request
const objects = objectsToDelete.map(key => ({ Key: key }));
const command = new DeleteObjectsCommand({
  Bucket: bucketName,
  Delete: {
    Objects: objects,
    Quiet: false
  }
});
try {
  const response = await client.send(command);
  console.log('Delete operation completed');
  if (response.Deleted && response.Deleted.length > 0) {
    console.log(`Successfully deleted ${response.Deleted.length} object(s):`);
    response.Deleted.forEach(deleted => {
      console.log(` - ${deleted.Key}`);
    });
  }
  if (response.Errors && response.Errors.length > 0) {
    console.log(`\nFailed to delete ${response.Errors.length} object(s):`);
    response.Errors.forEach(error => {
      console.log(` - ${error.Key}: ${error.Message}`);
    });
  }
} catch (err) {
  console.error('Failed to delete objects:', err);
}

获取对象元数据(HEAD)

const { HeadObjectCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const objectKey = 'my-object.txt';
const command = new HeadObjectCommand({
  Bucket: bucketName,
  Key: objectKey
});
try {
  const response = await client.send(command);
  console.log(`Object Metadata for '${objectKey}':`);
  console.log(` Content-Type: ${response.ContentType}`);
  console.log(` Content-Length: ${response.ContentLength} bytes`);
  console.log(` ETag: ${response.ETag}`);
  console.log(` Last-Modified: ${response.LastModified}`);
  if (response.Metadata && Object.keys(response.Metadata).length > 0) {
    console.log(' Custom Metadata:');
    for (const [key, value] of Object.entries(response.Metadata)) {
      console.log(`  ${key}: ${value}`);
    }
  }
} catch (err) {
  console.error('Failed to get object metadata:', err);
}

使用分块上传

对于大型文件,分段上传不仅能提高传输速率,还支持上传中途恢复。 每个部分的大小必须至少为 5 MB(最后一个部分除外)。

手动分批上传:

const {
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand,
  AbortMultipartUploadCommand
} = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const objectKey = 'large-object.dat';
try {
  // Step 1: Initiate multipart upload
  const createCommand = new CreateMultipartUploadCommand({
    Bucket: bucketName,
    Key: objectKey
  });
  const createResponse = await client.send(createCommand);
  const uploadId = createResponse.UploadId;
  console.log(`Multipart upload initiated with ID: ${uploadId}`);
  // Step 2: Upload parts (minimum 5MB per part except last)
  const completedParts = [];
  const minPartSize = 5 * 1024 * 1024; // 5MB
  // Create sample parts
  const parts = [
    'A'.repeat(minPartSize),
    'B'.repeat(minPartSize)
  ];
  for (let i = 0; i < parts.length; i++) {
    const partNumber = i + 1;
    const uploadPartCommand = new UploadPartCommand({
      Bucket: bucketName,
      Key: objectKey,
      PartNumber: partNumber,
      UploadId: uploadId,
      Body: parts[i]
    });
    try {
      const uploadResponse = await client.send(uploadPartCommand);
      completedParts.push({
        ETag: uploadResponse.ETag,
        PartNumber: partNumber
      });
      console.log(`Part ${partNumber} uploaded (ETag: ${uploadResponse.ETag})`);
    } catch (err) {
      // Abort multipart upload on error
      const abortCommand = new AbortMultipartUploadCommand({
        Bucket: bucketName,
        Key: objectKey,
        UploadId: uploadId
      });
      await client.send(abortCommand);
      throw err;
    }
  }
  // Step 3: Complete multipart upload
  const completeCommand = new CompleteMultipartUploadCommand({
    Bucket: bucketName,
    Key: objectKey,
    UploadId: uploadId,
    MultipartUpload: {
      Parts: completedParts
    }
  });
  const completeResponse = await client.send(completeCommand);
  console.log('Multipart upload completed successfully');
  console.log(`Location: ${completeResponse.Location}`);
  console.log(`ETag: ${completeResponse.ETag}`);
} catch (err) {
  console.error('Failed to complete multipart upload:', err);
}

使用上传管理器(推荐):

为了更方便地进行多部分上传,请使用 @ibm-cos/lib-storage 包:

const { Upload } = require('@ibm-cos/lib-storage');
const { S3Client } = require('ibm-cos-sdk-v2');
const fs = require('fs');
const fileStream = fs.createReadStream('large-file.bin');
const upload = new Upload({
  client: client,
  params: {
    Bucket: 'my-bucket',
    Key: 'large-file.bin',
    Body: fileStream
  },
  queueSize: 4, // Concurrent parts
  partSize: 5 * 1024 * 1024, // 5MB parts
  leavePartsOnError: false
});
// Track progress
upload.on('httpUploadProgress', (progress) => {
  console.log('Upload progress:', progress);
});
try {
  const result = await upload.done();
  console.log('Upload completed:', result);
} catch (err) {
  console.error('Upload failed:', err);
}

列出多部分上传

const { ListMultipartUploadsCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const command = new ListMultipartUploadsCommand({
  Bucket: bucketName
});
try {
  const response = await client.send(command);
  console.log(`In-progress multipart uploads in bucket '${bucketName}':`);
  if (response.Uploads && response.Uploads.length > 0) {
    response.Uploads.forEach(upload => {
      console.log(` Key: ${upload.Key}`);
      console.log(` Upload ID: ${upload.UploadId}`);
      console.log(` Initiated: ${upload.Initiated}`);
    });
  } else {
    console.log(' No in-progress uploads found');
  }
} catch (err) {
  console.error('Failed to list multipart uploads:', err);
}

列出多部分上传中的各个部分

列出了正在进行的多部分上传中已上传的所有部分。 在完成上传之前,可用于检查进度或收集 ETag。

const { ListPartsCommand } = require('ibm-cos-sdk-v2');
const command = new ListPartsCommand({
  Bucket: 'my-bucket',
  Key: 'my-large-object',
  UploadId: 'YOUR_UPLOAD_ID_HERE'
});
try {
  const response = await client.send(command);
  console.log('Parts listed successfully');
  if (response.Parts && response.Parts.length > 0) {
    response.Parts.forEach(p =>
      console.log(' - Part', p.PartNumber, '| ETag:', p.ETag, '| Size:', p.Size, 'bytes')
    );
  } else {
    console.log('No parts found.');
  }
} catch (err) {
  console.error('Error listing parts:', err);
}

从现有对象中复制一个部件

通过复制现有对象来上传一个部件。 当源数据已存在于 COS 中时,请使用此方法,而非上传原始字节。

const { UploadPartCopyCommand } = require('ibm-cos-sdk-v2');
const command = new UploadPartCopyCommand({
  Bucket: 'my-bucket',
  Key: 'my-large-object',
  UploadId: 'YOUR_UPLOAD_ID_HERE',
  PartNumber: 1,
  CopySource: 'my-bucket/source-object-key'
});
try {
  const response = await client.send(command);
  console.log('Part copy uploaded successfully');
  console.log('ETag:', response.CopyPartResult?.ETag);
} catch (err) {
  console.error('Error uploading part copy:', err);
}

设置存储桶生命周期配置

归档策略允许您在指定时间段过后,将对象自动迁移到归档存储类:

const { PutBucketLifecycleConfigurationCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
// Configure lifecycle rule to expire objects after 30 days
const command = new PutBucketLifecycleConfigurationCommand({
  Bucket: bucketName,
  LifecycleConfiguration: {
    Rules: [
      {
        Id: 'delete-old-logs',
        Status: 'Enabled',
        Filter: {
          Prefix: 'logs/',
        },
        Expiration: {
          Days: 30,
        },
      },
      {
        Id: 'cleanup-multipart-uploads',
        Status: 'Enabled',
        Filter: {
          Prefix: '',
        },
        AbortIncompleteMultipartUpload: {
          DaysAfterInitiation: 7,
        },
      },
    ]
  }
});
try {
  await client.send(command);
  console.log(`Lifecycle configuration set for bucket '${bucketName}'`);
} catch (err) {
  console.error('Failed to set lifecycle configuration:', err);
}

获取存储桶的生命周期配置

const { GetBucketLifecycleConfigurationCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const command = new GetBucketLifecycleConfigurationCommand({
  Bucket: bucketName
});
try {
  const response = await client.send(command);
  console.log(`Lifecycle rules for bucket '${bucketName}':`);
  if (response.Rules && response.Rules.length > 0) {
    response.Rules.forEach(rule => {
      console.log(` Rule ID: ${rule.ID}`);
      console.log(` Status: ${rule.Status}`);
      if (rule.Transitions && rule.Transitions.length > 0) {
        rule.Transitions.forEach(transition => {
          console.log(` Transition to ${transition.StorageClass} after ${transition.Days} days`);
        });
      }
    });
  } else {
    console.log(' No lifecycle rules found');
  }
} catch (err) {
  console.error('Failed to get lifecycle configuration:', err);
}

启用存储桶版本控制

const { PutBucketVersioningCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const command = new PutBucketVersioningCommand({
  Bucket: bucketName,
  VersioningConfiguration: {
    // Valid values: 'Enabled' | 'Suspended'
    Status: 'Enabled',
  },
});
try {
  await client.send(command);
  console.log(`Versioning enabled for bucket '${bucketName}'`);
} catch (err) {
  console.error('Failed to enable versioning:', err);
}

列出对象版本

const { ListObjectVersionsCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const command = new ListObjectVersionsCommand({
  Bucket: bucketName
});
try {
  const response = await client.send(command);
  console.log(`Object versions in bucket '${bucketName}':`);
  if (response.Versions && response.Versions.length > 0) {
    response.Versions.forEach(version => {
      console.log(` Key: ${version.Key}`);
      console.log(` Version ID: ${version.VersionId}`);
      console.log(` Is Latest: ${version.IsLatest}`);
      console.log(` Last Modified: ${version.LastModified}`);
    });
  } else {
    console.log(' No versions found');
  }
} catch (err) {
  console.error('Failed to list object versions:', err);
}

设置 CORS 配置

const { PutBucketCorsCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
// Set CORS configuration
const command = new PutBucketCorsCommand({
  Bucket: bucketName,
  CORSConfiguration: {
    CORSRules: [
      {
        AllowedHeaders: ['*'],
        AllowedMethods: ['GET', 'PUT', 'POST', 'DELETE'],
        AllowedOrigins: ['https://example.com'],
        ExposeHeaders: ['ETag'],
        MaxAgeSeconds: 3000
      }
    ]
  }
});
try {
  await client.send(command);
  console.log(`CORS configuration set for bucket '${bucketName}'`);
} catch (err) {
  console.error('Failed to set CORS configuration:', err);
}

设置对象标记

const { PutObjectTaggingCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const objectKey = 'my-object.txt';
// Set object tags
const command = new PutObjectTaggingCommand({
  Bucket: bucketName,
  Key: objectKey,
  Tagging: {
    TagSet: [
      {
        Key: 'Department',
        Value: 'Finance'
      },
      {
        Key: 'Project',
        Value: 'Q4-2024'
      },
      {
        Key: 'Classification',
        Value: 'Confidential'
      }
    ]
  }
});
try {
  await client.send(command);
  console.log(`Tags set for object '${objectKey}'`);
} catch (err) {
  console.error('Failed to set object tags:', err);
}

获取对象标签

const { GetObjectTaggingCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-bucket';
const objectKey = 'my-object.txt';
const command = new GetObjectTaggingCommand({
  Bucket: bucketName,
  Key: objectKey
});
try {
  const response = await client.send(command);
  console.log(`Tags for object '${objectKey}':`);
  if (response.TagSet && response.TagSet.length > 0) {
    response.TagSet.forEach(tag => {
      console.log(` ${tag.Key}: ${tag.Value}`);
    });
  } else {
    console.log(' No tags found');
  }
} catch (err) {
  console.error('Failed to get object tags:', err);
}

还原已归档的对象

归档存储类中的对象必须先进行还原,才能被访问:

const command = new RestoreObjectCommand({
  Bucket: bucketName,
  Key: objectKey,
  RestoreRequest: {
    Days: 7,
    GlacierJobParameters: {
      Tier: 'Bulk',
    },
  },
});
try {
  await client.send(command);
  console.log('Object restore initiated successfully');
  console.log(
    'Retrieval time depends on storage class: Vault typically 1-5 hours, Cold Vault typically 5-12 hours.'
  );
} catch (err) {
  console.error('Failed to restore object:', err);
}

注意:IBM Cloud Object Storage 仅支持“Bulk”检索层,用于从 Vault 和 Cold Vault 存储类中恢复对象。

设置对象保留策略

管理模式:拥有特定 IAM 权限的用户可在保留期内删除对象版本。

合规模式:在保留期内,任何用户均无法删除对象版本。

const { PutObjectRetentionCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-protected-bucket';
const objectKey = 'important-document.pdf';
// Set retention until a specific date
const retainUntil = new Date();
retainUntil.setDate(retainUntil.getDate() + 30);
const command = new PutObjectRetentionCommand({
  Bucket: bucketName,
  Key: objectKey,
  Retention: {
    Mode: 'COMPLIANCE',
    RetainUntilDate: retainUntil,
  },
});
try {
  await client.send(command);
  console.log('Object retention set successfully');
  console.log('RetainUntil:', retainUntil.toISOString());
} catch (err) {
  console.error('Error:', err.message);
}

获取对象保留时间

const { GetObjectRetentionCommand } = require('ibm-cos-sdk-v2');
const bucketName = 'my-protected-bucket';
const objectKey = 'important-document.pdf';
const command = new GetObjectRetentionCommand({
  Bucket: bucketName,
  Key: objectKey
});
try {
  const response = await client.send(command);
  console.log('Object retention retrieved successfully');
  console.log('Mode:', response.Retention?.Mode);
  console.log('RetainUntilDate:', response.Retention?.RetainUntilDate);
} catch (err) {
  console.error('Error:', err.message);
}

创建一个带有对象锁定的存储桶( S3 )

S3 对象锁定可在固定期限内或无限期地防止对象被删除或覆盖。 对象锁定必须在创建存储桶时启用——无法将其添加到现有存储桶中。

管理模式:拥有特定 IAM 权限的用户可在保留期内删除对象版本。

合规模式:在保留期内,任何用户均无法删除对象版本。

本节介绍 S3-compatible 的Object Lock功能。 有关 IBM 中 COS 特定的 WORM 保护功能,请参阅 “设置存储桶保护(WORM)”和 “管理法律保留”

const {
  CreateBucketCommand,
  PutObjectLockConfigurationCommand
} = require('ibm-cos-sdk-v2');
// Step 1: Create bucket with Object Lock enabled
const createCommand = new CreateBucketCommand({
  Bucket: 'my-locked-bucket',
  ObjectLockEnabledForBucket: true
});
try {
  await client.send(createCommand);
  console.log('Bucket created with Object Lock enabled');
} catch (err) {
  console.error('Error creating bucket:', err.message);
}
// Step 2: Set default retention rule
const lockConfigCommand = new PutObjectLockConfigurationCommand({
  Bucket: 'my-locked-bucket',
  ObjectLockConfiguration: {
    ObjectLockEnabled: 'Enabled',
    Rule: {
      DefaultRetention: {
        Mode: 'GOVERNANCE',
        Days: 30
      }
    }
  }
});
try {
  await client.send(lockConfigCommand);
  console.log('Default Object Lock configuration set successfully');
} catch (err) {
  console.error('Error setting lock config:', err.message);
}

设置“对象锁定”配置

设置或更新适用于上传到存储桶的每个新对象的默认保留规则。

const { PutObjectLockConfigurationCommand } = require('ibm-cos-sdk-v2');
const command = new PutObjectLockConfigurationCommand({
  Bucket: 'my-object-lock-bucket',
  ObjectLockConfiguration: {
    ObjectLockEnabled: 'Enabled',
    Rule: {
      DefaultRetention: {
        Mode: 'COMPLIANCE',
        Days: 2
      }
    }
  }
});
try {
  await client.send(command);
  console.log('Object lock configuration set successfully');
} catch (err) {
  console.error('Error:', err.message);
}

获取对象锁配置

const { GetObjectLockConfigurationCommand } = require('ibm-cos-sdk-v2');
const command = new GetObjectLockConfigurationCommand({
  Bucket: 'my-object-lock-bucket'
});
try {
  const response = await client.send(command);
  console.log('Object lock configuration retrieved successfully');
  console.log('ObjectLockEnabled:', response.ObjectLockConfiguration?.ObjectLockEnabled);
  console.log('Rule:', JSON.stringify(response.ObjectLockConfiguration?.Rule, null, 2));
} catch (err) {
  console.error('Error:', err.message);
}

检查存储桶是否存在(HEAD)

const { HeadBucketCommand } = require('ibm-cos-sdk-v2');
const command = new HeadBucketCommand({
  Bucket: 'my-bucket'
});
try {
  await client.send(command);
  console.log('Bucket exists');
} catch (err) {
  if (err.name === 'NotFound') {
    console.log('Bucket does not exist');
  } else {
    console.error('Error checking bucket:', err);
  }
}

从文件进行流式上传

const fs = require('fs');
const { PutObjectCommand } = require('ibm-cos-sdk-v2');
const fileStream = fs.createReadStream('large-file.bin');
const command = new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'large-file.bin',
  Body: fileStream
});
try {
  const response = await client.send(command);
  console.log('File uploaded successfully');
} catch (err) {
  console.error('Error uploading file:', err);
}

将流媒体内容下载到文件中

const fs = require('fs');
const { GetObjectCommand } = require('ibm-cos-sdk-v2');
const command = new GetObjectCommand({
  Bucket: 'my-bucket',
  Key: 'large-file.bin'
});
try {
  const response = await client.send(command);
  const fileStream = fs.createWriteStream('downloaded-file.bin');
  response.Body.pipe(fileStream);
  await new Promise((resolve, reject) => {
    fileStream.on('finish', resolve);
    fileStream.on('error', reject);
    response.Body.on('error', reject);
  });
  console.log('File downloaded successfully');
} catch (err) {
  console.error('Error downloading file:', err);
}

带分页功能地列出所有对象

v2 SDK 为返回截断结果的操作提供了内置的分页器。

使用分页器(推荐):

const { paginateListObjectsV2 } = require('ibm-cos-sdk-v2');
async function listAllObjects(bucket, prefix) {
  const allObjects = [];
  const paginator = paginateListObjectsV2(
    { client: client, pageSize: 1000 },
    { Bucket: bucket, Prefix: prefix }
  );
  try {
    for await (const page of paginator) {
      if (page.Contents) {
        allObjects.push(...page.Contents);
      }
    }
    console.log('Total objects:', allObjects.length);
    return allObjects;
  } catch (err) {
    console.error('Error listing objects:', err);
    throw err;
  }
}

手动分页:

const { ListObjectsV2Command } = require('ibm-cos-sdk-v2');
async function listAllObjects(bucket, prefix) {
  const allObjects = [];
  let continuationToken = undefined;
  do {
    const command = new ListObjectsV2Command({
      Bucket: bucket,
      Prefix: prefix,
      ContinuationToken: continuationToken
    });
    const response = await client.send(command);
    if (response.Contents) {
      allObjects.push(...response.Contents);
    }
    continuationToken = response.NextContinuationToken;
  } while (continuationToken);
  console.log('Total objects:', allObjects.length);
  return allObjects;
}

生成预签名的URL

预签名 URL 允许临时、无需身份验证地访问对象。 首先安装 presigner 软件包:

npm install @ibm-cos/s3-request-presigner

预签名的 GET URL (下载):

const { GetObjectCommand } = require('ibm-cos-sdk-v2');
const { getSignedUrl } = require('@ibm-cos/s3-request-presigner');
const command = new GetObjectCommand({
  Bucket: 'my-bucket',
  Key: 'my-object.txt'
});
try {
  const url = await getSignedUrl(client, command, { expiresIn: 3600 });
  console.log('Presigned URL:', url);
} catch (err) {
  console.error('Error generating presigned URL:', err);
}

预签名的 PUT URL (上传):

const { PutObjectCommand } = require('ibm-cos-sdk-v2');
const { getSignedUrl } = require('@ibm-cos/s3-request-presigner');
const command = new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'upload-object.txt',
  ContentType: 'text/plain'
});
try {
  const url = await getSignedUrl(client, command, { expiresIn: 3600 });
  console.log('Presigned PUT URL:', url);
} catch (err) {
  console.error('Error generating presigned URL:', err);
}

获取 CORS 的配置

const { GetBucketCorsCommand } = require('ibm-cos-sdk-v2');
const command = new GetBucketCorsCommand({
  Bucket: 'my-bucket'
});
try {
  const response = await client.send(command);
  console.log('CORS rules:', response.CORSRules);
} catch (err) {
  console.error('Error getting CORS configuration:', err);
}

删除 CORS 配置

const { DeleteBucketCorsCommand } = require('ibm-cos-sdk-v2');
const command = new DeleteBucketCorsCommand({
  Bucket: 'my-bucket'
});
try {
  await client.send(command);
  console.log('Bucket CORS configuration deleted successfully');
} catch (err) {
  console.error('Error deleting CORS:', err);
}

删除对象标签

const { DeleteObjectTaggingCommand } = require('ibm-cos-sdk-v2');
const command = new DeleteObjectTaggingCommand({
  Bucket: 'my-bucket',
  Key: 'my-object.txt'
});
try {
  await client.send(command);
  console.log('Object tagging deleted successfully');
} catch (err) {
  console.error('Error deleting object tags:', err);
}

上传带有自定义元数据的对象

const { PutObjectCommand } = require('ibm-cos-sdk-v2');
const command = new PutObjectCommand({
  Bucket: 'my-bucket',
  Key: 'my-object.txt',
  Body: 'content',
  Metadata: {
    'author': 'John Doe',
    'department': 'Engineering'
  }
});
try {
  await client.send(command);
  console.log('Object uploaded with metadata');
} catch (err) {
  console.error('Error uploading object:', err);
}

设置桶标签

const { PutBucketTaggingCommand } = require('ibm-cos-sdk-v2');
const command = new PutBucketTaggingCommand({
  Bucket: 'my-bucket',
  Tagging: {
    TagSet: [
      { Key: 'Environment', Value: 'Production' },
      { Key: 'Project', Value: 'WebApp' }
    ]
  }
});
try {
  await client.send(command);
  console.log('Bucket tags updated');
} catch (err) {
  console.error('Error updating bucket tags:', err);
}

删除存储桶的生命周期配置

const { DeleteBucketLifecycleCommand } = require('ibm-cos-sdk-v2');
const command = new DeleteBucketLifecycleCommand({
  Bucket: 'my-bucket'
});
try {
  await client.send(command);
  console.log('Lifecycle configuration deleted successfully');
} catch (err) {
  console.error('Error deleting lifecycle:', err);
}

设置桶访问控制列表 (ACL)

const { PutBucketAclCommand } = require('ibm-cos-sdk-v2');
const command = new PutBucketAclCommand({
  Bucket: 'my-bucket',
  ACL: 'public-read'
});
try {
  await client.send(command);
  console.log('Bucket ACL updated');
} catch (err) {
  console.error('Error updating bucket ACL:', err);
}

获取桶访问控制列表 (ACL)

const { GetBucketAclCommand } = require('ibm-cos-sdk-v2');
const command = new GetBucketAclCommand({
  Bucket: 'my-bucket'
});
try {
  const response = await client.send(command);
  console.log('Bucket ACL retrieved successfully');
  console.log('Owner:', response.Owner);
  console.log('Grants:', response.Grants);
} catch (err) {
  console.error('Error getting bucket ACL:', err);
}

设置对象访问控制列表 (ACL)

const { PutObjectAclCommand } = require('ibm-cos-sdk-v2');
const command = new PutObjectAclCommand({
  Bucket: 'my-bucket',
  Key: 'my-object.txt',
  ACL: 'public-read'
});
try {
  await client.send(command);
  console.log('Object ACL updated');
} catch (err) {
  console.error('Error updating object ACL:', err);
}

获取对象访问控制列表 (ACL)

const { GetObjectAclCommand } = require('ibm-cos-sdk-v2');
const command = new GetObjectAclCommand({
  Bucket: 'my-bucket',
  Key: 'my-object.txt'
});
try {
  const response = await client.send(command);
  console.log('Object ACL retrieved successfully');
  console.log('Owner:', response.Owner);
  console.log('Grants:', response.Grants);
} catch (err) {
  console.error('Error getting object ACL:', err);
}

获取版本控制状态

const { GetBucketVersioningCommand } = require('ibm-cos-sdk-v2');
const command = new GetBucketVersioningCommand({ Bucket: 'my-bucket' });
try {
  const response = await client.send(command);
  console.log('Bucket versioning configuration retrieved successfully');
  console.log('Status:', response.Status);
  // MFADelete is always undefined for IBM COS.
  console.log('MFADelete:', response.MFADelete);
} catch (err) {
  console.error('Error:', err.message);
}

获取特定对象的版本

const { GetObjectCommand } = require('ibm-cos-sdk-v2');
const command = new GetObjectCommand({
  Bucket: 'my-bucket',
  Key: 'my-file.txt',
  VersionId: '<VERSION_ID>'
});
try {
  const response = await client.send(command);
  console.log('Version ID:', response.VersionId);
  // Stream response.Body to a file or buffer as needed.
} catch (err) {
  console.error('Error:', err.message);
}

将对象上传到带版本控制的存储桶

启用版本控制后,每次调用 PutObjectCommand 都会创建一个新版本。 该响应包含新的 VersionId

const { PutObjectCommand } = require('ibm-cos-sdk-v2');
const command = new PutObjectCommand({
  Bucket: 'my-versioned-bucket',
  Key: 'my-file.txt',
  Body: 'Hello, World!'
});
try {
  const response = await client.send(command);
  console.log('Object uploaded successfully');
  console.log('Version ID:', response.VersionId);
} catch (err) {
  console.error('Error:', err.message);
}

删除特定的对象版本

通过包含其 VersionId,永久删除该对象的一个特定版本。 如果版本化存储桶中没有版本 ID,则会创建一个删除标记。

const { DeleteObjectCommand } = require('ibm-cos-sdk-v2');
const command = new DeleteObjectCommand({
  Bucket: 'my-versioned-bucket',
  Key: 'my-file.txt',
  VersionId: 'YOUR_VERSION_ID_HERE'
});
try {
  const response = await client.send(command);
  console.log('Object version deleted successfully');
  console.log('Deleted Version ID:', response.VersionId);
  console.log('Delete Marker:', response.DeleteMarker ? 'Yes' : 'No');
} catch (err) {
  console.error('Error:', err.message);
}

设置桶级保护(WORM)

IBM Cloud Object Storage 支持“一次写入、多次读取”(WORM)存储桶保护功能,以满足合规性和数据保留要求。

设置桶保护:

const { PutBucketProtectionConfigurationCommand } = require('ibm-cos-sdk-v2');
const command = new PutBucketProtectionConfigurationCommand({
  Bucket: 'my-protected-bucket',
  ProtectionConfiguration: {
    Status: 'Retention',
    MinimumRetention: { Days: 1 },
    DefaultRetention: { Days: 30 },
    MaximumRetention: { Days: 365 },
  },
});
try {
  await client.send(command);
  console.log('Bucket protection configuration set successfully');
} catch (err) {
  console.error('Error configuring protection:', err.message);
}

获取桶保护:

const { GetBucketProtectionConfigurationCommand } = require('ibm-cos-sdk-v2');
const command = new GetBucketProtectionConfigurationCommand({
  Bucket: 'my-protected-bucket'
});
try {
  const response = await client.send(command);
  console.log('Bucket protection configuration retrieved successfully');
  console.log('Response:', JSON.stringify(response, null, 2));
} catch (err) {
  console.error('Error getting protection config:', err);
}

创建一个采用 Key Protect 加密的存储桶

IBM Key Protect 为存储桶级加密提供加密密钥管理:

const { CreateBucketCommand } = require('ibm-cos-sdk-v2');
const command = new CreateBucketCommand({
  Bucket: 'my-encrypted-bucket',
  CreateBucketConfiguration: {
    LocationConstraint: 'us-south-standard'
  },
  IBMSSEKPEncryptionAlgorithm: 'AES256',
  IBMSSEKPCustomerRootKeyCrn: 'crn:v1:bluemix:public:kms:us-south:...'
});
try {
  await client.send(command);
  console.log('Encrypted bucket created');
} catch (err) {
  console.error('Error creating encrypted bucket:', err);
}

重命名对象

RenameObject 是 IBM 中一个COS特有的原子服务器端操作。 不会传输任何数据——仅密钥发生变化:

const { RenameObjectCommand } = require('ibm-cos-sdk-v2');
const command = new RenameObjectCommand({
  Bucket: 'my-bucket',
  Key: 'new-object-key',                    // destination key
  RenameSource: 'my-bucket/old-object-key'  // source: bucket/key
});
try {
  await client.send(command);
  console.log('Object renamed successfully');
} catch (err) {
  console.error('Error:', err.message);
}

更新对象加密

UpdateObjectEncryption 更新现有对象上的加密密钥引用。 要求该存储桶已配置 IBM、Key Protect 或HPCS:

const { UpdateObjectEncryptionCommand } = require('ibm-cos-sdk-v2');
const command = new UpdateObjectEncryptionCommand({
  Bucket: 'my-bucket',
  Key: 'my-object.txt'
});
try {
  await client.send(command);
  console.log('Object encryption updated successfully');
} catch (err) {
  console.error('Error:', err.message);
}

管理存储桶复制

获取复制配置:

const { GetBucketReplicationCommand } = require('ibm-cos-sdk-v2');
const command = new GetBucketReplicationCommand({ Bucket: 'my-bucket' });
try {
  const response = await client.send(command);
  console.log('Bucket replication configuration retrieved successfully');
  console.log('Rules:', JSON.stringify(response.ReplicationConfiguration?.Rules, null, 2));
} catch (err) {
  console.error('Error:', err.message);
}

删除复制配置:

const { DeleteBucketReplicationCommand } = require('ibm-cos-sdk-v2');
const command = new DeleteBucketReplicationCommand({ Bucket: 'my-bucket' });
try {
  await client.send(command);
  console.log('Bucket replication configuration deleted successfully');
} catch (err) {
  console.error('Error:', err.message);
}

列出复制故障:

const { ListBucketReplicationFailuresCommand } = require('ibm-cos-sdk-v2');
const command = new ListBucketReplicationFailuresCommand({ Bucket: 'my-bucket' });
try {
  const response = await client.send(command);
  console.log('Bucket replication failures listed successfully');
  console.log('Response:', JSON.stringify(response, null, 2));
} catch (err) {
  console.error('Error:', err.message);
}

重试失败的复制操作:

const { PutBucketReplicationReattemptCommand } = require('ibm-cos-sdk-v2');
const command = new PutBucketReplicationReattemptCommand({ Bucket: 'my-bucket' });
try {
  await client.send(command);
  console.log('Bucket replication reattempt triggered successfully');
} catch (err) {
  console.error('Error:', err.message);
}

创建会话

CreateSession 为 IBM Cloud Object Storage 存储桶生成一个临时会话令牌:

const { CreateSessionCommand } = require('ibm-cos-sdk-v2');
const command = new CreateSessionCommand({ Bucket: 'my-bucket' });
try {
  const response = await client.send(command);
  console.log('Session created successfully');
  console.log('Response:', JSON.stringify(response, null, 2));
} catch (err) {
  console.error('Error:', err.message);
}

等待资源准备就绪

等待器会不断轮询资源,直到其达到预期状态,从而无需手动轮询循环。

等待桶的出现:

const { waitUntilBucketExists } = require('ibm-cos-sdk-v2');
try {
  await waitUntilBucketExists(
    {
      client: client,
      maxWaitTime: 120, // Maximum wait time in seconds
      minDelay: 2,      // Minimum delay between checks in seconds
      maxDelay: 10      // Maximum delay between checks in seconds
    },
    { Bucket: 'my-bucket' }
  );
  console.log('Bucket exists and is ready');
} catch (err) {
  console.error('Bucket did not become available:', err);
}

等待某个对象存在:

const { waitUntilObjectExists } = require('ibm-cos-sdk-v2');
try {
  await waitUntilObjectExists(
    {
      client: client,
      maxWaitTime: 60,
      minDelay: 1,
      maxDelay: 5
    },
    {
      Bucket: 'my-bucket',
      Key: 'my-object.txt'
    }
  );
  console.log('Object exists and is ready');
} catch (err) {
  console.error('Object did not become available:', err);
}

后续步骤