本文最后更新于 2023-12-26。

Intro

Oracle Cloud 是由甲骨文驱动的公有云产品,其 Free Tier 计划包含了 20GB 的对象存储服务。由于其可用区位于海外,跨境访问对象存储时用户体验很不理想。我们可以使用 Cloudflare Workers 搭建反向代理,并配合缓存以节省开销。

Passthrough

直通模式下,Cloudflare Workers 直接转发请求和响应。

const REGION = "";
const BUCKET = "";
const NAMESPACE = "";
 
const BUCKET_URL = `https://objectstorage.${REGION}.oraclecloud.com/n/${NAMESPACE}/b/${BUCKET}/o`;
 
addEventListener("fetch", (event) => {
  event.respondWith(handle(event));
});
 
async function handle(event) {
  const pathname = new URL(event.request.url).pathname;
  return fetch(`${BUCKET_URL}${pathname}`);
}

Cache

缓存模式下,先使用 Cache API 将请求缓存于 Cloudflare 的 CDN ,再返回响应正文。

const REGION = "";
const BUCKET = "";
const NAMESPACE = "";
 
const BUCKET_URL = `https://objectstorage.${REGION}.oraclecloud.com/n/${NAMESPACE}/b/${BUCKET}/o`;
 
addEventListener("fetch", (event) => {
  event.respondWith(handle(event));
});
 
async function handle(event) {
  let request = event.request;
 
  if (["GET", "HEAD", "OPTIONS"].includes(request.method)) {
    const pathname = new URL(request.url).pathname;
    const cache = caches.default;
 
    let response;
    if (request.method === "GET") {
      // 缓存 GET 请求
      response = await cache.match(request);
      if (!response) {
        response = await fetch(`${BUCKET_URL}${pathname}`);
        let headers = Object.fromEntries(new Map(response.headers));
        headers["cache-control"] = "public, max-age=14400";
        response = new Response(response.body, { ...response, headers });
        event.waitUntil(cache.put(request, response.clone()));
      }
    } else {
      // 将非 GET 请求直接转发
      response = fetch(`${BUCKET_URL}${pathname}`, { method: request.method });
    }
 
    // override 错误信息以避免泄露 bucket 名称
    if (response.status === 404)
      return new Response("Not found", { status: 404 });
 
    // 允许浏览器直接播放 .mp4 文件而不触发下载
    if (pathname.endsWith(".mp4")) {
      headers = { "Content-Type": "video/mp4" };
      response = new Response(response.body, { ...response.body, headers });
    }
    return response;
  } else {
    return new Response("Method not allowed", { status: 405 });
  }
}

Eval

  • Before: 从境内直连对象存储,下载速度约为 50KB/s。
  • After: 在未使用自选 Cloudflare IP 的前提下,下载速度可达 6MB/s,提升 60~120x。

Ref