Nginx SSL 结合Tomcat 重定向URL变成HTTP的问题

背景:1、架构是用的是tomcat+nginx,框架是单体的springboot系列;nginx配置了证书,采用https访问

问题:发现用https访问首页之后,验证码加载不出来

解决:经排查发现验证码后台的链接变成了http,提示跨域访问,经百度查询,使用一下方案解决:Nginx SSL 结合Tomcat 重定向URL变成HTTP的问题 - 程序员大本营 (pianshen.com)

我采用的是第一种新增nginx配置,不需要改其它的,这个方案要求访问必须只能https访问,如果访问要求兼容https以及http的可以看一下最终解决方案(未检验)

防止网址内容找不到,把内容复制到下面:

 

问题描述

由于要配置服务器(Nginx + Tomcat)的SSL的问题(Nginx同时监听HTTPHTTPS),但是,如果用户访问的是HTTPS协议,然后Tomcat进行重定向的时候,却变成了HTTP.

 

逐步实践过程

在网上找了一些资料,有些是通过修改Nginx配置即可解决,也有只对Tomcat配置进行调整解决的… 各说不一,以下对尝试的解决过程进行记录:

实践一:Nginx新增配置

HTTP协议制转为https

Nginx代理的配置,要添加以下内容:

location / {
    proxy_pass http://test-server;
    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  $scheme;

    # 作用是对发送给客户端的URL进行修改, 将http协议强制转为https
    proxy_redirect   http:// https://;
}

为了方便测试proxy_redirect强制转换, http(80)、https(443)共存

server {
    listen  80;  
    listen  443 ssl;  
    ...
}

重定向测试

  • JAVA CODE:

  1.  
    HttpServletResponse resp = (HttpServletResponse)response;
  2.  
    resp.sendRedirect("/static/html/index.html");

使用HTTP协议访问nginx代理地址之后,URL被重定向为HTTPS协议了, 如下图所示:

 

当然直接使用HTTPS协议访问, 肯定也是没有问题的,如下图所示:

 

 

转发测试

  • JAVA CODE:

  1.  
    HttpServletResponse resp = (HttpServletResponse)response;
  2.  
    req.getRequestDispatcher("/static/html/index.html").forward(request, response);

测试结果与重定向一致, 无异常情况;

测试总结

实际应用场景中,如果要求HTTPHTTPS协议共存的时候(请求的协议与响应的协议一致)就会出现HTTP请求被强转为HTTPS,尝试将Nginx配置proxy_redirect http:// https://;注释,最终使用HTTPS协议亦无法正常跳转;

实践二:Tomcat新增配置

不修改Nginx的情况下, 仅对Tomcat配置进行调整

server.xmlEngine模块下面配置多一个以下的Valve

  1.  
    <Valve className="org.apache.catalina.valves.RemoteIpValve"
  2.  
    remoteIpHeader="X-Forwarded-For"
  3.  
    protocolHeader="X-Forwarded-Proto"
  4.  
    protocolHeaderHttpsValue="https"/>

重定向测试

使用HTTPS协议访问时,最终被重定向到HTTP

转发测试

使用HTTPS协议访问,转发动作未出现问题

测试总结

重定向的时候, HTTPS协议被转为HTTP,测试结果不通过。

实践三:终极方案

Nginx 配置

对过程一Nginx配置进行调整注释或删除proxy_redirect,最终如下:

location / {
    proxy_pass http://test-server;
    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  $scheme;
}

Tomcat 配置

参看:Tomcat配置

测试过程

HTTP协议请求

HTTPS协议请求

 

测试结果

测试通过,无论使用HTTP访问还是HTTPS访问,最终返回都是根据请求的协议进行响应,问题解决。

完整配置

  • Nginx
worker_processes  1;

events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    sendfile        on;

    keepalive_timeout  65;

    upstream test-server {  
        server 10.15.16.6:8280 weight=1;
    }

    server {
        listen       80;
        listen       443 ssl;
        server_name  localhost;

        #ssl_certificate      cert.pem;
        #ssl_certificate_key  cert.key;

        ssl_certificate      server.crt;
        ssl_certificate_key  server.key;

       # ssl_session_cache    shared:SSL:1m;
       #ssl_session_timeout  5m;

       # ssl_ciphers  HIGH:!aNULL:!MD5;
       # ssl_prefer_server_ciphers  on;


        location / {
            proxy_pass http://test-server;
            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  $scheme;
            # proxy_redirect   http:// https://;
        }

    }

}

//处理代码段

  1.  
    domainName = request.getRequestURL().toString();
  2.  
    String X_Forwarded_Proto = httpRequest.getHeader("X-Forwarded-Proto");
  3.  
    if(StringUtils.isNotBlank(X_Forwarded_Proto)){
  4.  
    if(X_Forwarded_Proto.toLowerCase().contains("https") && !domainName.toLowerCase().startsWith("https://")){
  5.  
    domainName = "https://" + domainName.substring(7);
  6.  
    }
  7.  
    }

 

posted @ 2021-08-27 09:20  小An  阅读(469)  评论(0编辑  收藏  举报