Beyond the Origin: How Cloudflare Workers Forge High-Performance APIs

Beyond the Origin: How Cloudflare Workers Forge High-Performance APIs

超越源站:Cloudflare Workers 如何打造高性能 API

As engineers, we spend a lot of time optimizing our origin servers. We scale them up, add more instances, and fine-tune our database queries. But what if the biggest performance gain wasn’t on our origin server at all? What if it was somewhere between our user and our server? 作为工程师,我们花费大量时间优化源服务器。我们进行扩容、增加实例并微调数据库查询。但如果最大的性能提升根本不在源服务器上呢?如果它位于用户和服务器之间的某个地方呢?

For years, the model has been simple: a user makes a request, it hits our infrastructure, we process it, and send a response. This is reliable, but it has limitations. Every request, good or bad, puts a load on our servers. Latency is dictated by the physical distance between the user and our data center. This is where edge computing, specifically with tools like Cloudflare Workers, changes the game. 多年来,模式很简单:用户发起请求,请求到达我们的基础设施,我们进行处理并发送响应。这种模式很可靠,但存在局限性。每一个请求(无论好坏)都会给服务器带来负载。延迟由用户与数据中心之间的物理距离决定。这就是边缘计算(特别是像 Cloudflare Workers 这样的工具)改变游戏规则的地方。

Workers are small, fast functions that run on Cloudflare’s global network. They intercept HTTP requests before they reach your origin server. This simple fact opens up a world of possibilities for building faster, more resilient, and more intelligent APIs. Workers 是运行在 Cloudflare 全球网络上的小型、快速函数。它们在 HTTP 请求到达源服务器之前将其拦截。这一简单的事实为构建更快、更具弹性且更智能的 API 开辟了无限可能。

The Old Path: A Quick Refresher

旧路径:快速回顾

Let’s quickly visualize the traditional journey of an API request. A user’s device sends a request. It travels across the internet to your data center, passes through a load balancer, hits one of your API servers, which then likely queries a database, and finally, the response travels all the way back. Every step in this chain adds latency. If your server is in Virginia and your user is in Tokyo, that’s a long round trip. 让我们快速直观地了解 API 请求的传统旅程。用户的设备发送请求,请求跨越互联网到达你的数据中心,通过负载均衡器,到达其中一台 API 服务器,服务器随后可能查询数据库,最后响应原路返回。链条中的每一步都会增加延迟。如果你的服务器在弗吉尼亚州而用户在东京,那将是一次漫长的往返。

Furthermore, your server has to spend CPU cycles on every single request, whether it’s for a simple data lookup or a malicious attempt to overload your service. This model has served us well, but it puts all the responsibility, and all the load, on your central infrastructure. 此外,你的服务器必须为每一个请求消耗 CPU 周期,无论是简单的查询还是恶意过载攻击。这种模式虽然服务了我们很久,但它将所有的责任和负载都压在了你的中心基础设施上。

The New Path: Intercepting Requests at the Edge

新路径:在边缘拦截请求

Cloudflare Workers introduce a new step right at the beginning of this process. When a request is made to your domain, it first hits a Cloudflare data center close to the user. Your Worker code runs right there, in that data center. Cloudflare Workers 在此过程的最开始引入了一个新步骤。当请求发送到你的域名时,它首先会到达离用户最近的 Cloudflare 数据中心。你的 Worker 代码就在那个数据中心运行。

This Worker can now make decisions: Can I answer this request myself from a cache? Is this request valid? Does it have the right authentication token? Should I modify this request before sending it to the origin? Should I route this request to a different origin server based on the user’s location? Only if the Worker decides to, does the request continue on to your origin server. This means you can handle many requests without ever touching your own infrastructure, saving you money and reducing load. 现在,Worker 可以做出决策:我能否直接从缓存中响应此请求?此请求是否有效?它是否有正确的身份验证令牌?在发送到源站之前,我是否应该修改此请求?我是否应该根据用户的位置将此请求路由到不同的源服务器?只有当 Worker 决定放行时,请求才会继续发送到你的源服务器。这意味着你可以在不触及自身基础设施的情况下处理大量请求,从而节省成本并降低负载。

As you can see, the Worker can serve responses directly from the edge (a cache hit), providing a massive speed boost. The origin server becomes the source of truth, not the first line of defense for every single request. 正如你所见,Worker 可以直接从边缘提供响应(缓存命中),从而带来巨大的速度提升。源服务器成为了“事实来源”,而不是每一个请求的第一道防线。

Four Practical Ways to Boost Your API with Workers

使用 Workers 提升 API 的四种实用方法

Theory is great, but let’s look at some real-world code examples. Workers are written in JavaScript or any language that compiles to WebAssembly, making them very accessible. 理论固然重要,但让我们看看一些实际的代码示例。Workers 使用 JavaScript 或任何可编译为 WebAssembly 的语言编写,这使得它们非常易于使用。

1. Supercharge Caching Beyond Simple Headers

1. 超越简单 Header 的缓存增强

Standard HTTP caching with Cache-Control headers is powerful but often blunt. What if you want to cache responses for anonymous users but always get fresh data for logged-in users? A Worker makes this simple. You can inspect the request for an authentication cookie or header and decide whether to serve a cached response. 使用 Cache-Control 头的标准 HTTP 缓存功能强大但往往比较粗糙。如果你想为匿名用户缓存响应,但又想让已登录用户始终获取最新数据,该怎么办?Worker 让这一切变得简单。你可以检查请求中的身份验证 Cookie 或 Header,并决定是否提供缓存响应。

// A simple Worker that caches based on user role
// 一个基于用户角色进行缓存的简单 Worker
export default {
  async fetch(request, env, ctx) {
    const cache = caches.default;
    let response = await cache.match(request);
    if (response) {
      console.log('Cache HIT');
      return response;
    }
    console.log('Cache MISS');

    // Check for an auth cookie. If it doesn't exist, the user is anonymous.
    // 检查身份验证 Cookie。如果不存在,则用户为匿名。
    const hasAuthCookie = request.headers.get('Cookie')?.includes('auth_token=');

    // Fetch from the origin server
    // 从源服务器获取
    const originResponse = await fetch(request);

    // Only cache responses for anonymous users and if the response was successful.
    // 仅在用户为匿名且响应成功时进行缓存。
    if (!hasAuthCookie && originResponse.ok) {
      const cacheableResponse = originResponse.clone();
      // Cache for 10 minutes
      // 缓存 10 分钟
      cacheableResponse.headers.set('Cache-Control', 'public, max-age=600');
      ctx.waitUntil(cache.put(request, cacheableResponse));
    }
    return originResponse;
  },
};

When to use this: Great for public-facing content on an API that also serves authenticated users. Think blog posts, product listings, or public profiles. 适用场景: 非常适合同时服务于已认证用户和公共内容的 API。例如博客文章、产品列表或公开个人资料。

When not to use this: Avoid this for highly personalized or sensitive data that should never be cached, even for a short time. 不适用场景: 避免用于高度个性化或敏感的数据,这些数据即使在短时间内也不应被缓存。

2. Reject Bad Requests Before They Cost You

2. 在请求造成成本前拒绝无效请求

Validating requests is critical. But why make your origin server do the work of decoding a JWT or checking a request body schema if the request is invalid anyway? You can do this at the edge and reject bad traffic immediately. 验证请求至关重要。但如果请求本身就是无效的,为什么还要让源服务器去解码 JWT 或检查请求体模式呢?你可以在边缘完成这些工作并立即拒绝不良流量。

// A Worker that validates a bearer token
// 一个验证 Bearer Token 的 Worker
async function isValidJwt(token) {
  if (!token) return false;
  try {
    const [header, payload] = token.split('.');
    const decodedPayload = JSON.parse(atob(payload));
    const isExpired = decodedPayload.exp < Date.now() / 1000;
    return !isExpired;
  } catch (e) {
    return false;
  }
}

export default {
  async fetch(request, env, ctx) {
    const authHeader = request.headers.get('Authorization');
    const token = authHeader?.replace('Bearer ', '');
    if (!(await isValidJwt(token))) {
      return new Response('Unauthorized', { status: 401 });
    }
    // If token is valid, proceed to the origin
    // 如果令牌有效,则继续发送到源站
    return fetch(request);
  },
};

When to use this: Perfect for protecting authenticated API endpoints. It acts as a global authentication gateway, ensuring that your origin only receives requests from legitimate users. 适用场景: 非常适合保护已认证的 API 端点。它充当全局身份验证网关,确保你的源站仅接收来自合法用户的请求。

When not to use this: For public endpoints that do not require authentication. 不适用场景: 不需要身份验证的公共端点。