在 nginx 中,`try_files` 配合 `internal` 指令的核心做法是:将用于处理静态资源或生成内容的 location 块标记为 `internal`,使其只能被服务器内部请求(如 `try_files` 的 fallback)访问,而拒绝客户端的直接 url 访问。具体操作是在定义该 location 时添加 `internal` 参数,并在 `try_files` 的最后一个参数指向该 location 的路径。这样,当用户直接访问该路径时,nginx 会返回 404 错误;而当通过其他 location 的 `try_files` 规则触发内部跳转时,请求会被正常处理。

如何配置 location 以阻止外部直接访问
要限制特定路径仅允许内部访问,只需在该 location 块中添加 `internal` 指令即可。例如,假设你有一个 `/assets/` 目录存放生成的静态文件,希望用户不能直接输入 `/assets/file.js` 访问,而是通过 `/app/` 下的逻辑间接获取。你可以将 `/assets/` 的 location 设为 internal。当客户端直接请求 `/assets/test.js` 时,Nginx 会立即返回 404 Not Found,因为该 location 不接受外部请求。只有当另一个 location(如 `/app/`)中的 `try_files` 尝试匹配到 `/assets/$uri` 并发生内部重定向时,请求才能进入这个 location 并被处理。

server {
listen 80;
server_name example.com;
# 主应用入口,尝试匹配文件,若不存在则交给 /assets/ 处理
location /app/ {
try_files $uri /assets/$uri =404;
}
# 内部资源目录,禁止外部直接访问
location /assets/ {
internal;
root /var/www/html;
# 如果找到文件则返回,否则 try_files 会继续向下或返回 404
try_files $uri =404;
}
}
在上述配置中,`/app/` 是对外暴露的入口。当用户访问 `/app/test.js` 时,Nginx 首先检查 `/var/www/html/app/test.js` 是否存在。如果不存在,它会将请求内部重定向到 `/assets/test.js`。此时,请求进入 `/assets/` location。由于该 location 标记了 `internal`,Nginx 会检查请求来源是否为内部。因为是 `try_files` 触发的内部重定向,所以请求被允许,接着执行 `try_files $uri =404;` 查找 `/var/www/html/assets/test.js`。如果文件存在,则返回内容;如果不存在,则返回 404。如果用户直接访问 `/assets/test.js`,请求来源是外部的,Nginx 直接拒绝并返回 404,不会进入该 location 的处理逻辑。
try_files 的 fallback 机制与 internal 的配合原理
`try_files` 的工作机制是按顺序检查文件或目录,如果所有列出的文件都不存在,则执行最后一个参数指定的动作。当最后一个参数是一个 URI(不以 `=` 开头且不是正则表达式)时,Nginx 会进行内部重定向(internal redirect),而不是返回 302 重定向。这种内部重定向的特点是请求的原始 URI 不变,但内部处理路径改变,且请求被视为“内部”请求。这正是 `internal` 指令生效的关键。`internal` 指令的作用是告诉 Nginx,只有内部重定向的请求才能进入该 location,外部客户端发起的请求将被拒绝。因此,通过将 `try_files` 的 fallback 指向一个带有 `internal` 标记的 location,可以实现一种“白名单”式的访问控制:只有经过特定逻辑(如权限校验、动态生成)后由 `try_files` 触发的请求才能访问这些资源,而直接猜测 URL 的用户无法访问。

# 另一种常见场景:隐藏实际的文件扩展名或路径结构
location /files/ {
# 尝试匹配 .html 文件,如果不存在,则尝试匹配 .json 文件
# 如果都不存在,则内部重定向到 /api/generate/ 处理
try_files $uri.html $uri.json /api/generate/$uri;
}
location /api/generate/ {
internal;
# 这里可以调用 proxy_pass 或其他逻辑来动态生成内容
# 例如,根据 $uri 从数据库获取数据并返回
return 200 "Generated content for: $uri";
}
在这个例子中,`/files/` location 负责处理对 `.html` 和 `.json` 文件的请求。如果用户请求 `/files/data`,Nginx 先检查 `data.html`,再检查 `data.json`。如果这两个文件都不存在,`try_files` 会将请求内部重定向到 `/api/generate/data`。由于 `/api/generate/` location 标记了 `internal`,用户不能直接访问 `/api/generate/data`,只能通过 `/files/` 的 fallback 机制间接获取。这种模式常用于实现伪静态页面或动态内容生成,同时隐藏后端的具体实现路径。
当 try_files 找不到文件且 fallback 指向 internal location 时会发生什么
当 `try_files` 遍历完所有列出的文件路径都未找到匹配项,并且最后一个参数指向一个带有 `internal` 标记的 location 时,Nginx 会执行内部重定向到该 location。如果该 location 能够成功处理请求(例如,找到了对应的文件或执行了代理),则返回相应的响应。如果该 location 也无法处理请求(例如,`try_files` 在其内部再次失败,或者没有合适的处理器),则最终会返回 404 错误。关键在于,如果用户试图直接访问这个 fallback 指向的 URI,由于 `internal` 指令的存在,Nginx 会直接拒绝请求并返回 404,而不会进入该 location 的处理流程。这确保了只有通过 `try_files` 等内部机制触发的请求才能访问这些资源,从而实现了访问控制。


















