banner
innei

innei

写代码是因为爱,写到世界充满爱!
github
telegram
twitter

缓存标头和利用边缘网络加速访问

本文以 Cloudflare + Vercel 为例。

了解缓存标头#

在生产中,我们通常会利用 Redis 去缓存接口数据。对于前端应用来说,我们一般会利用内容分发网络(CDN)去缓存页面和其他静态资源。

我们知道 HTTP 标头 cache-control 可以用来强缓存资源。

例如,cache-control: max-age=60 表示资源在 60 秒内不会过期,浏览器如果不使用强制刷新的话(例如请求标头含有cache-control: max-age=0)可以直接使用本地缓存。

在边缘网络或是内容分发网络中,一般都能相关的标头进行缓存。

比如:s-maxage 的值。

Note

s-maxage

The s-maxage response directive indicates how long the response remains fresh in a shared cache. The s-maxage directive is ignored by private caches, and overrides the value specified by the max-age directive or the Expires header for shared caches, if they are present.

Cache-Control: s-maxage=604800

参考:https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cache-Control#s-maxage

而这个值,一般都被 CDN 或者边缘网络用来控制缓存时间。

在 Vercel 中。Cache 章节中,告诉我们可以使用这个值去控制一个 API 响应的缓存时间。另外也提供了 Vercel 私有的 HTTP 标头,例如 Vercel-CDN-Cache-Control

在 Cloudflare 中,When to use CDN-Cache-Control
中的例子可以更好的帮助理解资源在各端的缓存控制。

Headers:

Cache-Control: max-age=14400, s-maxage=84000
Cloudflare-CDN-Cache-Control: max-age=24400
CDN-Cache-Control: max-age=18000

Cache behavior:

CachesCache TTL (seconds)
Origin Server Cache14400
Network Shared Cache84000
Cloudflare Edge24400
Other CDNs18000
Browser Cache14400

上表中,Cloudflare 可以消费响应头中的 cache-control: s-maxageCloudflare-CDN-Cache-Control 控制资源在 Cloudflare 分发网和边缘网络的缓存。

通过缓存标头,可以更快的让用户访问到资源,减少服务器的负载。

以 Vercel 部署的 Next.js 为例,下面我们来做一些优化,让短期并发的负载下减少服务器的真实请求。

Next.js API Route 的响应缓存#

这是一个简单的 Next.js API Route。

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export const GET = async (req: NextRequest) => {
  return NextResponse.json({})
}

现在我们可以增加缓存标头。

import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export const GET = async (req: NextRequest) => {
  return NextResponse.json(
    {},
    {
      headers: {
        'Cache-Control': 'max-age=60, s-maxage=86400',
        'CDN-Cache-Control': 'max-age=86400',
      },
    },
  )
}

现在把 API 使用 Cloudflare 代理。

在第一次请求之后,下一次请求中,我们能看到 Cloudflare 命中了缓存。

Cf-Cache-Status: HIT

使用 vercel.json 全局配置标头#

在单个 API 中,每每的添加缓存标头非常的麻烦并且我们也无法控制除了 API Route 之外的其他路由。我们可以使用 vercel.json 全局配置标头。

在项目根目录下新建 vercel.json,内容如下:

下面路由参考项目 Shiro,可按需配置路由。

{
  "headers": [
    {
      "source": "/",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "s-maxage=300, stale-while-revalidate=59"
        },
        {
          "key": "CDN-Cache-Control",
          "value": "max-age=300"
        },
        {
          "key": "Vercel-CDN-Cache-Control",
          "value": "max-age=300"
        }
      ]
    },
    {
      "source": "/og",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "s-maxage=3600, stale-while-revalidate=30"
        },
        {
          "key": "CDN-Cache-Control",
          "value": "max-age=3600"
        },
        {
          "key": "Vercel-CDN-Cache-Control",
          "value": "max-age=3600"
        }
      ]
    },
    {
      "source": "/api/(.*)",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "s-maxage=60, stale-while-revalidate=30"
        },
        {
          "key": "CDN-Cache-Control",
          "value": "max-age=60"
        },
        {
          "key": "Vercel-CDN-Cache-Control",
          "value": "max-age=60"
        }
      ]
    },
    {
      "source": "/feed",
      "headers": [
        {
          "key": "Cache-Control",
          "value": "s-maxage=86400, stale-while-revalidate=3600"
        },
        {
          "key": "CDN-Cache-Control",
          "value": "max-age=86400"
        },
        {
          "key": "Vercel-CDN-Cache-Control",
          "value": "max-age=86400"
        }
      ]
    }
  ]
}

使用 Vercel 提供的配置,可以对每个路由进行缓存标头的配置。配置过后,Vercel 会在响应这些请求时,自动添加缓存标头,然后经过 Cloudflare 读取缓存标头,然后在 Cloudflare 网络进行缓存,在下次请求到达时,直接从 Cloudflare 缓存中读取。

stale-while-revalidate= 的值控制了一个资源在过期后,多久内仍然可以使用过期资源,然后在后台异步更新资源,那么在即便过期的场景下,用户也能快速的获取到资源,加快页面加载。

[!IMPORTANT]

路由的匹配是从下到上的,那么也就是说,第一项可以定义为全局 Fallback 也就是路由匹配 /(.*)

参考:https://vercel.com/docs/projects/project-configuration#headers

Vercel 边缘网缓存#

你可能也注意到 Vercel-CDN-Cache-Control 这个标头。这个标头是 Vercel 私有的标头,用来控制资源在 Vercel 边缘网络的缓存。既然 Vercel 也提供了缓存,为什么还要使用 Cloudflare 呢?

我想大概有下面的原因:

  1. Cloudflare 一般作为 DNS 提供商,他会有着更加快速的响应时间。
  2. Vercel 的缓存命中很奇怪,有时候会命中,有时候不会命中,让我跟费解;而 Cloudflare 的缓存命中符合文档,在意料之中。

此文由 Mix Space 同步更新至 xLog
原始链接为 https://innei.in/posts/tech/vercel-cloudflare-http-header-about-cache


加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。