缓存响应
对于保持网站尽可能快速,缓存响应至关重要,无论是对于页面还是中间件。
一个很好的默认设置是对所有响应使用stale-while-revalidate缓存。
例如,我们可以在根布局 (src/routes/layout.tsx
) 中添加一个 onGet
导出,如下所示,以应用全站的良好缓存默认设置:
import { component$, Slot } from "@builder.io/qwik";
import type { RequestHandler } from "@builder.io/qwik-city";
export const onGet: RequestHandler = async ({ cacheControl }) => {
cacheControl({
// 默认情况下始终提供缓存响应,最多可以过期一周
staleWhileRevalidate: 60 * 60 * 24 * 7,
// 每 5 秒最多一次,在服务器上重新验证以获取此页面的新版本
maxAge: 5,
});
};
export default component$(() => {
return (
<main class="mx-auto max-w-[2200px] relative">
<Slot />
</main>
);
});
通过上述设置,我们不仅可以获得更好的性能(页面始终从缓存中立即提供),还可以显著降低托管成本,因为我们的服务器(或边缘函数)每个页面每 5 秒最多只需要运行一次。
cacheControl
任何接受请求事件的方法都可以调用 request.cacheControl
来设置响应的缓存控制头:
import type { RequestHandler } from "@builder.io/qwik-city";
export const onGet: RequestHandler = async ({ cacheControl }) => {
cacheControl({
public: true,
maxAge: 5,
sMaxAge: 10,
staleWhileRevalidate: 60 * 60 * 24 * 365,
});
};
您也可以覆盖这个设置。例如,也许您在根目录上有一个默认的缓存设置,但是想要禁用特定页面的缓存,您可以使用嵌套布局来覆盖这个设置:
import type { RequestHandler } from "@builder.io/qwik-city";
// 为 /dashboard 页面覆盖缓存设置,不缓存,因为它们对每个访问者都是唯一的
export const onGet: RequestHandler = async ({ cacheControl }) => {
cacheControl({
public: false,
maxAge: 0,
sMaxAge: 0,
staleWhileRevalidate: 0,
});
};
您可以查看完整的API 参考,了解可以传递给 request.cacheControl
的选项。
不适合缓存的情况
缓存是一个很好的默认设置,但并不适用于所有页面的所有时间。如果您的网站上有一些 URL,这些 URL 会向不同的人显示不同的内容 - 例如仅供已登录用户查看的页面,或者根据用户的位置显示不同内容的页面,您不应该使用响应中的缓存控制头对这些页面进行缓存,并且在服务器端根据访问者的情况渲染这些页面的内容。
对于对每个人都相同的高流量页面,例如主页,缓存是性能和成本方面的最佳选择。但是对于仅供已登录用户查看的页面,由于流量可能较少,禁用缓存可能是明智的。
您可以根据需要使用任何逻辑条件性地更改缓存行为:
import type { RequestHandler } from "@builder.io/qwik-city";
export const onGet: RequestHandler = async ({ cacheControl, url }) => {
// 只有我们的主页是公开的,并且应该被 CDN 缓存。其他页面对每个访问者都是唯一的
if (url.pathname === '/') {
cacheControl({
public: true,
maxAge: 5,
staleWhileRevalidate: 60 * 60 * 24 * 365,
});
}
};
CDN 缓存控制
为了更好地控制缓存策略,您的 CDN 可能有另一层缓存控制头。
cacheControl
便捷方法可以接收第二个参数(默认设置为 "Cache-Control"
)。您可以传递任何特定于您的 CDN 的字符串值,例如 "CDN-Cache-Control"、"Cloudflare-CDN-Cache-Control"、"Vercel-CDN-Cache-Control" 等。
cacheControl({
maxAge: 5,
staleWhileRevalidate: 60 * 60 * 24 * 365,
}, "CDN-Cache-Control");
缺失的控制
某些 CDN(例如 Vercel Edge)可能会剥离一些 "Cache-Control" 头。
如果您设置了没有 CDN-Cache-Control 的 Cache-Control,则 Vercel Edge 网络会在将响应发送到浏览器之前从响应中剥离 s-maxage 和 stale-while-revalidate。要确定响应是否来自缓存,请检查响应中的 x-vercel-cache 头。
因此,如果您的 CDN 默认情况下剥离了一些缓存控制头(例如 Vercel Edge),并且您希望浏览器使用 "stale-while-revalidate" 或 "s-maxage",您可以添加另一个 cacheControl
:
import type { RequestHandler } from "@builder.io/qwik-city";
export const onGet: RequestHandler = async ({ cacheControl }) => {
// 如果您希望浏览器使用 "stale-while-revalidate" 或 "s-maxage" 缓存控制头,您必须在 Vercel Edge 上添加第二个带有 "CDN-Cache-Control" 或 "Vercel-CDN-Cache-Control" 的 cacheControl
cacheControl({
staleWhileRevalidate: 60 * 60 * 24 * 365,
maxAge: 5,
});
cacheControl({
maxAge: 5,
staleWhileRevalidate: 60 * 60 * 24 * 365,
}, "CDN-Cache-Control");
};