Nginx 400 Bad Request: The plain HTTP request was sent to HTTPS port

Nginx


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中不包括访问端口。

第二种

server{
        listen 80;
        server_name example.com www.example.com;
        return 301 https://www.example.com$request_uri;
}

server {
        listen 443 ssl http2;
        server_name example.com www.example.com;

        root   /var/www/html/example.com/;
        index index.php index.html index.htm;
        
        access_log /var/log/nginx/example.com/example.com_access_log;
        error_log   /var/log/nginx/example.com/example.com_error_log   error;

        ssl on;
        ssl_certificate /etc/ssl/certs/example_com_cert_chain.crt;
        ssl_certificate_key /etc/ssl/private/example_com.key;
        ssl_session_timeout       5m;
        ssl_protocols             TLSv1 TLSv1.1 TLSv1.2;
  		ssl_ciphers               AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
        ssl_prefer_server_ciphers on;
        
        include /etc/nginx/ssl.d/ssl.conf;
		location / {
		   proxy_set_header  X-Real-IP  $remote_addr;
		   proxy_set_header  X-Forwarded-For $proxy_add_x_forwarded_for;
		   proxy_set_header  Host $http_host;
		   proxy_redirect    off;
		   expires           off;
		   sendfile          off;
		   proxy_pass        http://wpdev;
		   #  try_files $uri $uri/ /index.php?$query_string;
	   }
}
  location / {
               proxy_set_header Host $host:$server_port;
                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 $scheme;

             #判断是https请求,就直接跳转,然后断开这个连接不希望往下执行

                if ($scheme = 'https') {
                  proxy_pass http://gatewayservice;     
                  break;
                }

#上面做了判断,所以现在是http访问,会跟下面location的@http_to_https进行关联

                try_files $uri $uri/ @http_to_https;  
                index  index.html index.htm;
        }

       location @http_to_https {
          proxy_set_header Host $host:$server_port;
          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 $scheme;
          proxy_pass http://gatewayservice;
       }
proxy_redirect http:// $scheme://;

另外通过错误页面重定向
解决思路
将此错误页面重定向到指定的https地址即可

解决方法
假设端口号是8443:

server {
listen 8443 ssl;
ssl_certificate ssl_cert.pem;
ssl_certificate_key ssl_server.key;
server_name your_domain.com;
error_page 497 https:// h o s t host hosturi?$args;
location / {

}
}

另外,如果是自有域名,http和https端口都使用默认端口的话,只要将http的请求重定向到https即可

server {
listen 80;
listen 443 ssl;
ssl_certificate ssl_cert.pem;
ssl_certificate_key ssl_server.key;
server_name your_domain.com;
if (KaTeX parse error: Expected '}', got 'EOF' at end of input: …rn 301 https://host u r i ? uri? uri?args;
}
location / {

}
}

server
{
  # 开启Https
  listen 443 ssl;
  # 配置证书,免费证书怎么申请这边就不多说了。在晚上搜索腾讯云或者阿里云免费证书申请即可
  ssl_certificate /etc/nginx/conf.d/cert/4351595_www.xxx.pem;
  ssl_certificate_key /etc/nginx/conf.d/cert/4351595_www.xxx.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 xxx;
  index index.html index.htm index.php;
  root /data/wwwroot/wordpress;
  error_log /var/log/nginx/wordpress-error.log crit;
  access_log /var/log/nginx/wordpress-access.log;

  # 这边用于包含其他配置
  include extra/*.conf;
  include conf.d/rewrite/wordpress.conf;

}

# 将Http请求转化成Https请求
server {
  listen 80;
  server_name xxx;
  rewrite ^/(.*) https://$server_name$request_uri? permanent;
  //rewrite ^(.*)$ https://${server_name}$1 permanent; 
  // 或者 return 301 https://$server_name$request_uri;
  // rewrite ^(.*)$ https://$host$1 permanent;
}
  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值