nginx反向代理https内部定向到http报302的问题及解决

 更新时间:2023年12月22日 15:19:59   作者:shihuc  
这篇文章主要介绍了nginx反向代理https内部定向到http报302的问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教

环境信息

Linux:Linux i-8emt1zr1 2.6.32-573.el6.x86_64 #1 SMP Wed Jul 1 18:23:37 EDT 2015 x86_64 x86_64 x86_64 GNU/Linux

nginx:nginx version: openresty/1.9.3.2

Tomcat:Server version: Apache Tomcat/7.0.64

1. 问题描述

我们开发的客服系统,因为消息的到来,有的谷歌浏览器(V62)不支持http的消息提醒,要求https,故而,我们的系统,要将系统改造成https模式,另外,我们的系统,也有必要转化为https,为后续推广做准备。

2. 系统架构

LB+nginx+tomcat集群

3. 当前配置情况

SSL证书配置在LB上,nginx和tomcat服务器上,任然采用http协议通讯。

即LB在接收到客户浏览器https请求消息后,将转发给LB下挂载的nginx上,都是以http的方式转发,nginx对这些请求进行反向代理,代理到后面的tomcat服务器上。

4. 遇到的问题

客服系统,有权限控制,基于tomcat的web应用,用户登录后,执行redirect跳转到指定的服务页面。

就是这个跳转,遇到了问题,redirect在这里都被当做http跳转了。

登录前的样子:

登录后的样子:

问题主要发生在Tomcat7上,验证过tomcat8,是不存在问题的。

5. 如何解决

针对Tomcat7的这个问题,思路很简单,重点是解决redirect的时候,通知客户端浏览器以正确的scheme(https还是http)进行再次发起请求。

问题是, nginx这个时候收到的请求是来自LB的http请求了,怎么弄?其实是有办法的,可以利用HttpRequest中的referer字段,这个字段的含义,自行科普吧。

将referer的请求scheme信息,用来作为当前请求的scheme,如此可以保证所有的请求都是同一个scheme,不会因为redirect而遗漏信息。

nginx里面相应的配置如下:

location /CSS/websocket {
            proxy_pass http://css_ws_svr;
            proxy_set_header Host $host;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "upgrade";
        }

        location /CSS {
            proxy_pass http://css_svr;
            proxy_set_header Host $host;
            proxy_set_header Remote_Addr $remote_addr;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            set $mscheme $scheme;
            if ($http_referer ~* ^https.*) {
                set $mscheme "https";
            }
            proxy_set_header X-Forwarded-Proto $mscheme;
        }

如上配置,经过nginx反向代理后的HttpServletRequest中header部分就带上了字段X-Forwarded-Proto。

另外一方面,就是tomcat里面,要做一个配置,让tomcat在解析请求和做重定向的时候,知道用什么协议。

主要的配置在server.xml里面的Engine下,定义一个Value元素。

具体配置如下:

<Engine name="Catalina" defaultHost="localhost">

      
      <Realm className="org.apache.catalina.realm.LockOutRealm">
        <!-- This Realm uses the UserDatabase configured in the global JNDI
             resources under the key "UserDatabase".  Any edits
             that are performed against this UserDatabase are immediately
             available for use by the Realm.  -->
        <Realm className="org.apache.catalina.realm.UserDatabaseRealm"
               resourceName="UserDatabase"/>
      </Realm>

      <Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true">
        
        <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
               prefix="localhost_access_log." suffix=".txt"
               pattern="%h %l %u %t &quot;%r&quot; %s %b" />

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

        <Context path="/CSS" docBase="/home/tomcat/app/cssv2"/>
      </Host>
    </Engine>

这个配置里面,重点是protocolHeader字段,意思就是说,当protocolHeader字段的值为protocolHeaderHttpsValue的https的时候,认为是安全连接,否则就是http的非安全连接。

对应的代码逻辑,可以看org.apache.catalina.valves.RemoteIpValve这个类的源码

public void invoke(org.apache.catalina.connector.Request request, Response response)
 throws IOException, ServletException
{
......
if (protocolHeader != null) {
    String protocolHeaderValue = request.getHeader(protocolHeader);
    if (protocolHeaderValue != null)
    {

        if (protocolHeaderHttpsValue.equalsIgnoreCase(protocolHeaderValue)) {
            request.setSecure(true);
            
            request.getCoyoteRequest().scheme().setString("https");
        
            setPorts(request, httpsServerPort);
        } else {
            request.setSecure(false);
                
            request.getCoyoteRequest().scheme().setString("http");
                
            setPorts(request, httpServerPort);
        }
    }
}
......
}

经过上面的分析和配置修改,最终很灵活的实现https和http同时工作。

搞定这个问题,重点还是要对Http协议工作的流程有所了解,才能很容易的找到解决问题的思路。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • nginx学习总结五(nginx反向代理)

    nginx学习总结五(nginx反向代理)

    Nginx代理与负载均衡配置与优化技巧,方便需要的朋友
    2012-11-11
  • 前端项目中Nginx配置指南详解

    前端项目中Nginx配置指南详解

    这篇文章主要为大家详细介绍了在前端项目开发中如何配置Nginx,文中的示例代码讲解详细,具有一定的学习价值,感兴趣的小伙伴可以了解一下
    2023-09-09
  • linux下Nginx+Tomcat负载均衡配置方法

    linux下Nginx+Tomcat负载均衡配置方法

    这篇文章主要介绍了linux下Nginx+Tomcat负载均衡配置方法,需要的朋友可以参考下
    2016-09-09
  • 详解Nginx反向代理WebSocket响应403的解决办法

    详解Nginx反向代理WebSocket响应403的解决办法

    本篇文章主要介绍了详解Nginx反向代理WebSocket响应403的解决办法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01
  • 基于Nginx+lua实现简单的XSS攻击拦截

    基于Nginx+lua实现简单的XSS攻击拦截

    WAF即web应用防火墙,Nginx是一个主流的代理服务,除了本身的Nginx日志,作为用户肯定也支持对请求信息进行操作, 很多都是通过在代理服务器上挂载规则特征,实现软件层面的软WAF进行WEB防护,本文主要给大家介绍了Nginx+Lua实现一个简单的XSS攻击拦截,需要的朋友可以参考下
    2024-01-01
  • 使用nginx.exe时闪退的原因和解决方法

    使用nginx.exe时闪退的原因和解决方法

    最近使用老师给的nginx.exe时,点击nginx.exe突然屏幕就闪一下,经过一番排查,发现是端口被占用所导致的,所以本文就给大家讲讲端口被占用时的解决方法详细步骤,需要的朋友可以参考下
    2023-07-07
  • Nginx之rewrite实现URL重写方式

    Nginx之rewrite实现URL重写方式

    文章介绍了Nginx的rewrite模块,包括其重要性、相关指令(如set、if、break、return、rewrite)的使用方法和作用域,并举例说明了这些指令的实际应用场景,如域名重定向和防盗链处理
    2025-03-03
  • 如何用Nginx解决前端跨域问题

    如何用Nginx解决前端跨域问题

    在开发静态页面时,类似Vue的应用,我们常会调用一些接口,这些接口极可能是跨域,这篇文章主要介绍了如何用Nginx解决前端跨域问题,非常具有实用价值,需要的朋友可以参考下
    2019-01-01
  • Windows Server 2016 MySQL数据库安装配置详细安装教程

    Windows Server 2016 MySQL数据库安装配置详细安装教程

    这篇文章主要介绍了Windows Server 2016 MySQL数据库安装配置详细安装教程,需要的朋友可以参考下
    2017-08-08
  • nginx代理后端路径获取IP为127.0.0.1问题

    nginx代理后端路径获取IP为127.0.0.1问题

    文章讨论了在使用Nginx作为反向代理时,如何正确配置以避免在前端路径A/api访问后端时丢失真实的IP地址,通过有效的Nginx配置,可以确保在前后端分离的场景中,客户端通过前端路径访问后端时,后端能够正确获取客户端的真实IP地址,示例配置展示了如何实现这一目标
    2025-02-02

最新评论