Nginx報錯“The plain HTTP request was sent to HTTPS port”問題解決辦法

轉載自:https://blog.yoodb.com/yoodb/article/detail/1527

Nginx HTTP服務器的報錯“400 Bad Request: The plain HTTP request was sent to HTTPS port”,本文將講解如何解決這個問題。簡單從報錯的字面意思上來看,是因爲HTTP請求被髮送到HTTPS端口,這種報錯多出現在Nginx既處理HTTP請求又處理HTTPS請求的情況。

以下是Nginx常用的SSL配置(出於安全原因,我們使用了本站域名),配置文件將讓Nginx偵聽80和443端口,並將所有的HTTP請求重定向到HTTPS:

server {
    listen       443;
    server_name blog.yoodb.com;
    charset UTF-8;
    ssl on;
    ssl_certificate   /usr/local/nginx/conf/ssl/blog/2539791_blog.yoodb.com.pem;
    ssl_certificate_key  /usr/local/nginx/conf/ssl/blog/2539791_blog.yoodb.com.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;
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_pass http://172.17.6.114:8082;
    }
    location ~*/upload/images/ { 
    expires 1h;
        root /mnt/app/project/files;
    }
    location ~*/dynamic/images/ {
    expires 1h;
        root /mnt/app/project/files;
    }
}

以上的配置看上去都很正常,但是用戶請求如果通過80端口來訪問網站時,例如使用http://blog.yoodb.com,那麼這個請求就會在瀏覽器收到錯誤nginx 400 bad request“The plain HTTP request was sent to HTTPS port”,示例圖片如下:

Nginx報這種錯誤是因爲每一次用戶請求試圖通過HTTP訪問你的網站,這個請求被重定向到HTTPS。於是Nginx預計使用SSL交互,但原來的請求(通過端口80接收)是普通的HTTP請求,於是會產生錯誤。

另一方面,如果一個用戶使用https://blog.yoodb.com訪問網站,他們就不會遇到上述錯誤。此外,如果你有其他的網站配置爲不使用SSL,Nginx會嘗試使用HTTPS,這種情況下也會造成上述錯誤。

解決辦法:

將上面配置文中的“ssl on; ” 註釋掉或者修改成 “ssl off;”;“listen 443;”修改爲“listen 443 ssl”;新增“listen 80”,這樣Nginx就可以同時處理HTTP請求和HTTPS請求了,具體參考如下:

server {
    listen       80
    listen       443 ssl;
    server_name blog.yoodb.com;
    charset UTF-8;
    ssl_certificate   /usr/local/nginx/conf/ssl/blog/2539791_blog.yoodb.com.pem;
    ssl_certificate_key  /usr/local/nginx/conf/ssl/blog/2539791_blog.yoodb.com.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;
    if ($scheme = http) {
        return 301 https://$host$request_uri;
    }
    location / {
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_pass http://172.17.6.114:8082;
    }
    location ~*/upload/images/ { 
        expires 1h;
        root /mnt/app/project/files;
    }
    location ~*/dynamic/images/ {
        expires 1h;
        root /mnt/app/project/files;
    }
}

java redirect重定向https跳轉http問題,如果https訪問nginx通過nginx proxy_pass到http的tomcat服務正常能夠訪問,但是java redirect就跳轉到http,導致報錯“400 Bad Request: The plain HTTP request was sent to HTTPS port”。

解決辦法:

proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_pass http://172.17.6.114:8082;
proxy_redirect http:// https://;

實現流程是根據nginx的不同執行階段,來完成Location http到https。 

1)proxy_pass執行前,先設置了request head host 爲https外網訪問的域名+端口 

2)proxy_pass執行後,tomcat結果返回response 

3)proxy_redirect修改response中的location中的協議http爲https外網訪問的協議。 

注:java redirect重定向主要是通過訪問tomcat服務的請求head項來決定的,默認是http協議,域名是通過讀取host地址,默認host中不包括訪問端口。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章