在 nginx 中实现 cdn 缓存未命中时的本地降级,核心做法是利用 try_files 指令按优先级依次检查文件是否存在。当请求到达时,nginx 会先尝试匹配 cdn 上的资源路径,若该路径不存在(即 cdn 未命中),则自动回退到服务器本地的静态目录进行查找。通过这种链式检查机制,无需编写复杂的 lua 脚本或正则表达式,即可确保优先使用 cdn 内容,并在 cdn 失效或缺失时无缝切换至本地源站。

如何配置 try_files 实现 CDN 与本地回退
要实现这一功能,需要在 location 块中定义一个包含多个路径的 try_files 列表。第一个参数通常对应 CDN 的路径映射,第二个参数对应本地文件系统的路径,最后一个参数作为兜底处理未找到的情况。例如,假设 CDN 域名是 cdn.example.com,本地资源存储在 /var/www/html,配置时应将 CDN 路径放在前面,本地路径放在后面。这样,Nginx 会先尝试从 CDN 获取,如果返回 404 或文件不存在,则继续尝试本地路径。

server {
listen 80;
server_name example.com;
location /assets/ {
# 首先尝试 CDN 路径,如果不存在则尝试本地路径
# $uri 代表当前请求的 URI
# @fallback 是一个内部重定向标签,用于处理最终未找到的情况
try_files https://cdn.example.com$uri /assets$uri @fallback;
}
location @fallback {
return 404 "Resource not found on CDN or local server";
}
}
上述配置中,try_files 的第一个参数 https://cdn.example.com$uri 并不是一个文件系统路径,而是一个 URL。Nginx 默认情况下 try_files 只能检查文件系统路径。因此,直接对 URL 使用 try_files 是不生效的。正确的做法是使用 proxy_pass 结合 try_files 或者更常见的做法是:利用 try_files 检查本地文件,如果本地没有,再反向代理到 CDN。但题目要求的是“CDN 未命中时本地降级”,这通常意味着用户访问的是主域名,而 CDN 是加速层。如果是指 Nginx 作为边缘节点,那么逻辑应该是:先查本地缓存,如果没有,再去源站或 CDN 拉取。但根据常见场景,这里指的是 Nginx 作为前端网关,优先指向 CDN,CDN 失败则回源到本地存储。由于 try_files 不支持直接检查远程 URL,我们需要换一种思路:使用 if 判断或 map 变量,或者更简单地,如果 CDN 和本地路径有重叠,可以直接用 try_files 检查本地路径,但这不符合“CDN 优先”的逻辑。实际上,最标准的“CDN 优先,本地降级”架构中,Nginx 并不直接做这个决策,而是由 DNS 或客户端决定。但如果必须在 Nginx 层面实现,且 CDN 和本地资源在同一台机器或可访问的网络中,可以使用 sub_filter 或 proxy_pass。然而,针对 try_files 的具体用法,它主要用于本地文件系统的回退。因此,更准确的解释是:try_files 本身不能直接检查 CDN URL。如果要实现 CDN 未命中时本地降级,通常是在 CDN 配置中设置回源地址为本机 Nginx,或者在 Nginx 中使用 proxy_pass 到 CDN,并设置 error_page 来捕获 CDN 的 404 并重新请求本地文件。但既然题目指定了 try_files,我们假设场景是:Nginx 同时托管了 CDN 镜像和本地源文件,希望优先使用 CDN 镜像(可能通过不同的 URI 前缀区分),如果 CDN 镜像不存在,则使用本地源文件。例如,CDN 镜像存放在 /var/www/cdn,本地源文件存放在 /var/www/local。配置如下:
server {
listen 80;
server_name example.com;
location / {
# 先尝试 CDN 镜像路径
try_files /cdn$uri /local$uri =404;
}
}
在这个例子中,如果请求 /style.css,Nginx 会先检查 /var/www/cdn/style.css 是否存在。如果存在,直接返回;如果不存在,则检查 /var/www/local/style.css。如果两者都不存在,则返回 404。这种方式实现了基于文件存在的降级,而非基于 HTTP 响应的降级。如果需要基于 HTTP 响应(如 CDN 返回 500)进行降级,则需要使用 error_page 和 internal 重定向,但这超出了 try_files 的直接能力范围。因此,try_files 适用于“CDN 镜像文件存在性”的降级,而非“CDN 服务可用性”的降级。
try_files 在多路径回退中的执行顺序是怎样的
try_files 的执行顺序是从左到右依次检查。Nginx 会按照参数列表中给出的路径顺序,逐一检查文件是否存在。一旦找到第一个存在的文件或匹配的正则表达式,就立即停止检查并返回该结果。如果所有列出的路径都不存在,则使用最后一个参数指定的处理方式,通常是返回一个错误码或重定向到一个内部位置。这种顺序执行机制确保了优先级的明确性,开发者可以通过调整参数顺序来控制资源的加载优先级。例如,在上面的例子中,/cdn$uri 排在 /local$uri 之前,意味着 CDN 镜像具有更高的优先级。如果 CDN 镜像存在,即使本地源文件也存在,Nginx 也会返回 CDN 镜像的内容。只有当 CDN 镜像不存在时,才会去检查本地源文件。这种机制非常高效,因为 Nginx 在找到第一个匹配项后就会停止后续的检查,减少了不必要的 I/O 操作。

# 假设请求 /image.png # 1. 检查 /var/www/cdn/image.png -> 不存在 # 2. 检查 /var/www/local/image.png -> 存在,返回该文件 # 3. 如果 /var/www/local/image.png 也不存在,则触发 =404
需要注意的是,try_files 的最后一个参数如果是以 = 开头的错误码(如 =404),则必须提供,否则 Nginx 会报错。此外,最后一个参数也可以是一个内部重定向标签,如 @fallback,这样可以执行更复杂的逻辑,比如记录日志、修改响应头等。在使用内部重定向时,需要确保对应的 location @name 块已经定义。这种灵活性使得 try_files 不仅能处理简单的文件回退,还能集成到更复杂的应用流程中。例如,可以先尝试静态文件,如果不存在,则重定向到 PHP 处理器进行动态生成。这种模式在 WordPress 等 CMS 系统中非常常见,用于实现伪静态 URL 的支持。
当 CDN 和本地路径都缺失时如何处理
当 CDN 镜像和本地源文件都不存在时,try_files 会根据最后一个参数的设定进行处理。如果最后一个参数是 =404,Nginx 会直接返回 404 Not Found 状态码。如果最后一个参数是内部重定向标签,如 @fallback,Nginx 会将请求转发到对应的 location @fallback 块中。在该块中,可以定义更详细的错误处理逻辑,例如返回自定义的错误页面、记录错误日志或触发告警。这种处理方式确保了即使在所有资源都缺失的情况下,系统也能给出明确的反馈,而不是抛出内部错误或挂起请求。在实际生产中,建议始终为 try_files 提供一个明确的兜底处理方案,以避免因配置不当导致的意外行为。例如,可以设置一个默认的 404 页面,或者重定向到一个维护页面,告知用户资源暂时不可用。这种健壮性的设计对于提升用户体验和系统稳定性至关重要。











