Cloudflare R2白嫖使用指南 - Cloudflare银魂 - 科技改变生活 - 万事屋

Cloudflare R2白嫖使用指南

Cloudflare R2存储允许开发人员存储大量非结构化数据,而无需支付与典型云存储服务相关的昂贵出口带宽费用。

购买R2

在创建第一个存储桶之前,您必须在Cloudflare仪表板中购买R2。(使用易贝卡就可以)

20240704151305216-image

购买R2:

  1. 登录Cloudflare仪表板
  2. 帐户主页中,选择R2
  3. 选择购买R2计划
  4. 选择继续查看付款详情以查看您的付款。
  5. 选择返回 R2以前往 R2 面板。

20240704151345596-image

R2 的配额限制

在公测期间,R2 有如下的配额限制:

  • 每个账户可新建1000个存储桶
  • 每个存储桶可存储无限个对象
  • 每个对象大小最大5TB
  • 单次最大上传大小5GB,可多次分段上传
  • 每秒1000次的 A 类操作
  • 每秒250次的 B 类操作

A 类操作包括ListBuckets、PutBucket、ListObjects、PutObject、CopyObject、CompleteMultipartUpload、CreateMultipartUpload、UploadPart、UploadPartCopy

B 类操作包括HeadBucket、HeadObject和GetObject

免费操作包括DeleteObject、DeleteBucket、DeleteMultipartUpload

R2 的收费价格

R2 存储的价格要比目前的存储服务都低,有一部分免费额度,免费额度用完以后才开始计费:

  • 存储费用:每个月10GB免费额度,超出后每个月每 GB 收取 $0.015 的存储费用
  • A 类操作费用:每个月一百万次免费额度,超出后每百万次收取 $4.50 的操作费用
  • B 类操作费用:每个月一千万次免费额度,超出后每百万次收取 $0.36 的操作费用

由上可见价格比现有的存储服务厂商低的多,AWS 的 S3 是不是瑟瑟发抖?

创建存储桶

点击创建-输入名称-提交就好了

20240704151404421-image

造个Workers访问你的桶

打开workers,创建一个workers服务

并填入下面的代码

addEventListener("fetch", event => {
    event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
    const url = new URL(request.url)
    const objectName = url.pathname.slice(1)

    console.log(`${request.method} object ${objectName}: ${request.url}`)

    if (request.method === 'GET' || request.method === 'HEAD') {
        if (objectName === '') {
            if (request.method == 'HEAD') {
                return new Response(undefined, { status: 400 })
            }

            const options = {
                prefix: url.searchParams.get('prefix') ?? undefined,
                delimiter: url.searchParams.get('delimiter') ?? undefined,
                cursor: url.searchParams.get('cursor') ?? undefined,
                include: ['customMetadata', 'httpMetadata'],
            }
            console.log(JSON.stringify(options))

            const listing = await R2.list(options)
            return new Response(JSON.stringify(listing), {
                headers: {
                    'content-type': 'application/json; charset=UTF-8',
                }
            })
        }

        if (request.method === 'GET') {
            const range = parseRange(request.headers.get('range'))
            const object = await R2.get(objectName, {
                range,
                onlyIf: request.headers,
            })

            if (object === null) {
                return objectNotFound(objectName)
            }

            const headers = new Headers()
            //object.writeHttpMetadata(headers)
            headers.set('etag', object.httpEtag)
            const status = object.body ? (range ? 206 : 200) : 304
            return new Response(object.body, {
                headers,
                status
            })
        }

        const object = await R2.head(objectName, {
            onlyIf: request.headers,
        })

        if (object === null) {
            return objectNotFound(objectName)
        }

        const headers = new Headers()
        //object.writeHttpMetadata(headers)
        headers.set('etag', object.httpEtag)
        return new Response(null, {
            headers,
        })
    }
    if (request.method === 'PUT' || request.method == 'POST') {
        const object = await R2.put(objectName, request.body, {
            httpMetadata: request.headers,
        })
        return new Response(null, {
            headers: {
                'etag': object.httpEtag,
            }
        })
    }
    if (request.method === 'DELETE') {
        await R2.delete(url.pathname.slice(1))
        return new Response()
    }

    return new Response(`Unsupported method`, {
        status: 400
    })
}

function parseRange(encoded) {
    if (encoded === null) {
        return
    }

    const parts = encoded.split("bytes=")[1]?.split("-") ?? []
    if (parts.length !== 2) {
        throw new Error('Not supported to skip specifying the beginning/ending byte at this time')
    }

    return {
        offset: Number(parts[0]),
        length: Number(parts[1]) + 1 - Number(parts[0]),
    }
}

function objectNotFound(objectName) {
    return new Response(`<html><body>R2 object "<b>${objectName}</b>" not found</body></html>`, {
        status: 404,
        headers: {
            'content-type': 'text/html; charset=UTF-8'
        }
    })
}

20240704151424503-image

在worker首页的设置-变量-R2 存储桶绑定,编辑变量,新建一个,左侧变量名称填入R2,右侧选择你的R2存储桶,保存

20240704151437769-image

2.默认情况下未指定路径,方式为get时会列出所有key,根据路径能下载文件
3.详细解析我将稍后贴出,之后会写在自己博客上,如果你看得懂那也可以自己看
4.这个脚本是能够进行A类操作,也就是可以修改/删除R2,如果只读的话请自行删除

如何加速?

使用第三方CFCDN平台接入你的域名

例如面板 | CloudFlare CDN合作接入管理平台-挖站否 – (wzfou.com)

在worker首页的触发器-自定义域-添加你的域名

20240704151507245-image

如何访问?

例如你上传了一个名为abc.jpg的文件

访问地址就为https://abc.com/abc.jpg

附录

workers.dev  目前不怎么好访问,直连打不开属正常,建议使用特殊方法(绑定自己的域名加速,看上面的方法)

本文转自点滴记忆:阅读原文

    请登录后查看回复内容

万事屋新帖