r2存储的sdk接入及调用

455 阅读1分钟

对于r2存储桶、存储对象的增、删、读取等操作,官方提供了sdk使用示例:

developers.cloudflare.com/r2/examples…

提供示例项目:github.com/itMrBoy/cf_…

导入sdk

import {
    S3Client,              // S3 客户端,用于与 R2 服务交互
    ListBucketsCommand,    // 列出所有存储桶的命令
    ListObjectsV2Command,  // 列出存储桶中对象的命令
    GetObjectCommand,      // 获取对象的命令
    PutObjectCommand,      // 上传对象的命令
} from "@aws-sdk/client-s3";

新建一个s3客户端

/**
 * 从环境变量获取 Cloudflare R2 配置信息
 * 包括账户ID、访问密钥ID和密钥
 */
const config = {
    ACCOUNT_ID: process.env.CLOUDFLARE_ACCOUNT_ID,
    ACCESS_KEY_ID: process.env.CLOUDFLARE_R2_ACCESS_KEY_ID,
    SECRET_ACCESS_KEY: process.env.CLOUDFLARE_R2_SECRET_ACCESS_KEY
};

/**
 * 初始化 S3 客户端
 * 配置 Cloudflare R2 的访问端点和认证信息
 */
const S3 = new S3Client({
    region: "auto",
    endpoint: `https://${config.ACCOUNT_ID}.r2.cloudflarestorage.com`,
    credentials: {
        accessKeyId: config.ACCESS_KEY_ID || "",
        secretAccessKey: config.SECRET_ACCESS_KEY || "",
    },
});

ACCOUNT_ID、ACCESS_KEY_ID、SECRET_ACCESS_KEY位置

image.png

image.png

管理API令牌 / 创建API令牌

创建时可以指定令牌的操作权限

image.png

创建API令牌后,需要记录一下 ACCESS_KEY_ID ​和 SECRET_ACCESS_KEY​,后续无法查看,如果忘记只能通过轮转的形式重新生成,原ACCESS_KEY_ID ​和 SECRET_ACCESS_KEY​作废

image.png

存储桶的上传、获取

上传文件到 R2 存储桶

/**
 * 上传文件到 R2 存储桶
 * @param bucketName - 存储桶名称
 * @param key - 文件在存储桶中的路径/名称
 * @param fileContent - 文件内容,支持 Buffer、Uint8Array 或字符串
 * @param contentType - 文件内容类型(可选)
 * @returns 包含上传结果的 Promise
 */
export async function uploadFile(
    bucketName: string,
    key: string,
    fileContent: Buffer | Uint8Array | string,
    contentType?: string
): Promise<{success: boolean, message: string, data?: object}> {
    try {
        const command = new PutObjectCommand({
            Bucket: bucketName,
            Key: key,
            Body: fileContent,
            ContentType: contentType,
        });

        const result = await S3.send(command);
        
        return {
            success: true,
            message: "文件上传成功",
            data: result
        };
    } catch (error) {
        console.error("上传文件时出错:", error);
        return {
            success: false,
            message: `文件上传失败: ${error instanceof Error ? error.message : '未知错误'}`
        };
    }
}

获取所有可用的存储桶列表

/**
 * 获取所有可用的存储桶列表
 * @returns 包含存储桶列表的 Promise
 */
export async function listBuckets(): Promise<{success: boolean, message: string, data?: object}> {
    try {
        const result = await S3.send(new ListBucketsCommand({}));
        return {
            success: true,
            message: "获取存储桶列表成功",
            data: result
        };
    } catch (error) {
        console.error("获取存储桶列表时出错:", error);
        return {
            success: false,
            message: `获取存储桶列表失败: ${error instanceof Error ? error.message : '未知错误'}`
        };
    }
}

存储桶内文件对象的上传、获取

获取指定存储桶中的所有对象列表

/**
 * 获取指定存储桶中的所有对象列表
 * @param bucketName - 存储桶名称
 * @returns 包含对象列表的 Promise
 */
export async function listObjects(bucketName: string): Promise<{success: boolean, message: string, data?: object}> {
    try {
        const result = await S3.send(new ListObjectsV2Command({ Bucket: bucketName }));
        return {
            success: true,
            message: "获取对象列表成功",
            data: result
        };
    } catch (error) {
        console.error("获取对象列表时出错:", error);
        return {
            success: false,
            message: `获取对象列表失败: ${error instanceof Error ? error.message : '未知错误'}`
        };
    }
}

从 R2 存储桶下载文件

/**
 * 从 R2 存储桶下载文件
 * @param bucketName - 存储桶名称
 * @param key - 文件在存储桶中的路径/名称
 * @returns 包含文件内容的 Promise,文件内容以 ArrayBuffer 形式返回
 */
export async function downloadFile(
    bucketName: string,
    key: string
): Promise<{success: boolean, message: string, data?: ArrayBuffer}> {
    try {
        const command = new GetObjectCommand({
            Bucket: bucketName,
            Key: key,
        });

        const result = await S3.send(command);
        
        if (!result.Body) {
            return {
                success: false,
                message: "文件不存在"
            };
        }

        // 将流转换为ArrayBuffer
        const chunks: Uint8Array[] = [];
        const reader = result.Body.transformToWebStream().getReader();
        
        while (true) {
            const { done, value } = await reader.read();
            if (done) break;
            chunks.push(value);
        }

        const buffer = Buffer.concat(chunks);
        
        return {
            success: true,
            message: "文件下载成功",
            data: buffer.buffer
        };
    } catch (error) {
        console.error("下载文件时出错:", error);
        return {
            success: false,
            message: `文件下载失败: ${error instanceof Error ? error.message : '未知错误'}`
        };
    }
}