Flask+Nginx反向代理ssl报错The plain HTTP request was sent to HTTPS port解决办法

2022年6月24日01:15:38 发表评论 4,418 ℃

最近通过Nginx反向代理一个网站,环境为Flask+uwsgi+Nginx反向代理,当部署证书并设置强制跳转https以后,在浏览器输入:blog.amd5.cn访问出现了“400 Bad Request The plain HTTP request was sent to HTTPS port”错误,如下图:

Flask+Nginx反向代理ssl报错The plain HTTP request was sent to HTTPS port解决办法

一开始怀疑自己的配置有问题,反复确认和对比以后,排除配置问题。

于是网上搜索了相关报错,找到了解决方案,出现这种报错的主要原因是:

因为HTTP请求被发送到HTTPS端口,这种报错多出现在Nginx既处理HTTP请求又处理HTTPS请求的情况。

正常80端口访问应该是:http://blog.amd5.cn:80/login

正常开启HTTPS以后443端口访问应该是:https://blog.amd5.cn:443/login

但是此时却变成了: http://blog.amd5.cn:443/login,即HTTP请求被发送到HTTPS端口。

如果我直接在浏览器输入:https://blog.amd5.cn,却能正常跳转到https://blog.amd5.cn/login

直接输入http://blog.amd5.cn/login,也能正常跳转到https://blog.amd5.cn/login

为什么会有这样的问题呢,经过排查原来是多次重定向导致的,主要是因为在使用Flask-Login验证登录的时候,如果未登录,会重定向到登录页面。

通过浏览器开发者工具,可以看到,当我浏览器输入blog.amd5.cn,第一次重定向为http->https:

Request URL: https://blog.amd5.cn/
Request Method: GET
Status Code: 302 FOUND
Remote Address: 127.0.0.1:443
Referrer Policy: strict-origin-when-cross-origin

然后第二次重定向为:/->/login:

Request URL: http://blog.amd5.cn:443/login
Request Method: GET
Status Code: 400 Bad Request
Remote Address: 127.0.0.1:443
Referrer Policy: strict-origin-when-cross-origin

简单来说就是:当第一次请求试图通过HTTP访问网站blog.amd5.cn,这个请求被重定向到HTTPS。于是Nginx预计使用SSL(443端口)交互,但原来的请求(通过端口80接收,即检查到未登录,需要从/跳转到/login)是普通的HTTP请求,于是会产生错误。

解决方法是在原来的配置上面加两个参数:

proxy_set_header X-Forwarded-Proto https; # X-Forwarded-Proto(XFP)报头是用于识别协议HTTP或HTTPS的,即用户客户端实际连接到代理或负载均衡的标准报头。
proxy_redirect http:// https://  # proxy_redirect 该指令用来修改被代理服务器返回的响应头中的Location头域和“refresh”头域,也就是把http协议改成https协议。

添加以后完整的配置如下:

server {
listen 443 ssl;
ssl_certificate /conf/ssl/blog.amd5.cn.pem;
ssl_certificate_key /conf/ssl/blog.amd5.cn.key;
ssl_session_timeout 5m;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE:ECDH:AES:HIGH:!NULL:!aNULL:!MD5:!ADH:!RC4;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;
server_name  blog.amd5.cn;
#代理配置
location /{
proxy_set_header X-Original-Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host blog.amd5.cn:$server_port;
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://127.0.0.1:5000/;
proxy_redirect http:// https://;
}
}
server{
listen 80 ;
server_name blog.amd5.cn;
#代理配置
location /{
proxy_set_header X-Original-Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host blog.amd5.cn:$server_port;
proxy_pass http://127.0.0.1:5000/;
}
add_header X-Cache $upstream_cache_status;
proxy_cache_key $host$uri$is_args$args;
if ($scheme = http) {
    return 301 https://$host$uri?$args;
 }
}

再次测试访问正常:

Flask+Nginx反向代理ssl报错The plain HTTP request was sent to HTTPS port解决办法

两次请求:

Request URL: https://blog.amd5.cn/
Request Method: GET
Status Code: 302 FOUND
Remote Address: 127.0.0.1:443
Referrer Policy: strict-origin-when-cross-origin

Request URL: https://blog.amd5.cn/login
Request Method: GET
Status Code: 200 OK
Remote Address: 127.0.0.1:443
Referrer Policy: strict-origin-when-cross-origin
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: