Nginx 通过 if ($scheme = "http") { return 497; } 拦截 HTTP 请求,再用 error_page 497 指向 internal 的自定义提示页(如 /upgrade-https.html),实现非重定向的 HTTPS 升级提示;497 是 Nginx 自定义状态码,专用于“请升级到 HTTPS”语义。

Nginx 本身不直接识别“不安全请求”这个概念(比如 HTTP 请求未强制跳转 HTTPS),它没有内置的 is_secure 布尔判断指令。所谓“客户端发起不安全请求”,通常指用户通过 HTTP 访问本应只走 HTTPS 的站点。这时真正的处理逻辑是:检测 scheme 是否为 http,然后重定向或返回提示页面。
要实现“返回自定义升级提示页面”(而非直接 301 跳转),关键在于:用 if ($scheme = http) 拦截请求,并用 error_page + return 或 rewrite + internal 组合,让 Nginx 主动触发一个可映射的错误码(如 497),再由 error_page 497 指向你的提示页。
这是 Nginx 官方推荐且稳定的方式,因为 if 在 location 外虽受限,但在 server 块中用于简单变量判断(如 $scheme)是安全且被允许的。
使用 497 状态码返回 HTTPS 升级提示页
HTTP 状态码 497 是 Nginx 自定义的非标准码,专用于“HTTP 请求被发送到 HTTPS 端口”,但也可主动触发,作为“请升级到 HTTPS”的语义标识。
✅ 正确配置步骤:
server {
listen 80;
server_name example.com;
# 主动拦截 HTTP 请求,返回 497 错误(非重定向)
if ($scheme = "http") {
return 497;
}
# 定义 497 错误页
error_page 497 /upgrade-https.html;
# 确保该页面可被内部访问(禁止外部直接 GET /upgrade-https.html)
location = /upgrade-https.html {
internal;
root /usr/share/nginx/html; # 确保路径下存在 upgrade-https.html
add_header Content-Type text/html;charset=utf-8;
}
}⚠️ 注意:
return 497必须写在if中(不能用rewrite ... break替代),否则 Nginx 不会触发error_page 497。
自定义提示页内容示例(/usr/share/nginx/html/upgrade-https.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>请使用 HTTPS 访问</title>
<style>body{font-family:sans-serif;text-align:center;padding:60px;background:#f8f9fa;} h1{color:#2c3e50;} .btn{display:inline-block;padding:10px 20px;background:#3498db;color:white;text-decoration:none;border-radius:4px;}</style>
</head>
<body>
<h1>? 安全连接已启用</h1>
<p>本网站仅支持 HTTPS 加密访问。</p>
<p><a href="https://example.com" class="btn">立即切换到安全连接</a></p>
<small>如无法自动跳转,请手动在地址栏开头添加 <code>https://</code></small>
</body>
</html>确保该文件存在、Nginx 用户(如 www-data 或 nginx)有读取权限,且 MIME 类型正确(add_header 非必需,但可防浏览器误判)。
? 替代方案:用 302 临时重定向(更常见,但不是“返回页面”)
如果你实际想要的是友好提示+自动跳转,可改用:
if ($scheme = "http") {
return 302 https://$server_name$request_uri;
}但这不满足“返回提示页面”的要求——它直接跳转,用户看不到提示页。
❌ 常见误区与避坑
-
if块内不能包含root、proxy_pass等复杂指令,但return安全可用; - 不要用
error_page 400 /...或403替代 497 —— 它们语义不符,且可能与其他逻辑冲突; -
location = /upgrade-https.html必须加internal,否则用户可通过 URL 直接访问,失去控制; - 若启用了
fastcgi_intercept_errors或proxy_intercept_errors(如反向代理 PHP/后端),需确认它们不拦截 497(默认不拦截,因 497 非标准码); - 测试时用
curl -I http://example.com看响应头是否为HTTP/1.1 497,再检查 HTML 内容是否返回。
Nginx 对“不安全请求”的响应本质是协议层判断,靠 if + return 497 + error_page 这一组合最简洁、可靠、语义清晰。


















