Flask+Nginx反向代理ssl報錯The plain HTTP request was sent to HTTPS port解決辦法

2022年6月24日01:15:38 發表評論 4,232 ℃

最近通過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: