redirect跳转https变为http问题的深入思考

背景

  1. 服务部署以及跳转展示如下:
    redirect跳转https变为http问题的深入思考_第1张图片
    redirect跳转https变为http问题的深入思考_第2张图片

  2. 用户https请求通过阿里云负载通过http到指定应用,应用返回跳转路径(状态为302),但跳转路径为http(不为https),所以访问不了
    2.1 跳转伪代码:

    // ModelAndView
    mv.setViewName(WebCst.REDIRECT + "/admin/sso/login");
    

    2.2 浏览器跳转截图
    redirect跳转https变为http问题的深入思考_第3张图片

结论总结

  1. 用nginx负载返回给浏览器的Location为https是因为nginx做了处理,关键配置见下

    proxy_set_header    Host   $host;
    proxy_redirect http:// https://;
    

    1.1 用arthas的trace命令观察线上,应用直接返回的Location为http://localhost:8232/exp-admin/admin/sso/login

    	watch org.apache.catalina.connector.Response toAbsolute -x 2
    
  2. 将nginx替换成SLB后,返回给浏览器的Loaction变为http是因为SLB缺少相应的配置
    2.1 SLB相关配置:https://help.aliyun.com/document_detail/97646.html

跳转的Location是如何生成的

  1. 后台是以springboot进行开发的,下面的分析都是基于springboot方式进行

  2. 先展示一下springmvc的工作原理
    redirect跳转https变为http问题的深入思考_第4张图片
    2.1 我们跳转设置为:mv.setViewName(WebCst.REDIRECT + “/admin/sso/login”); 结合上图,猜测根据视图进行跳转
    redirect跳转https变为http问题的深入思考_第5张图片
    2.2 视图解析器ContentNegotiatingViewResolver通过resolveViewName解析视图,得到跳转视图:RedirectView,调用其render进行跳转

  3. 以RedirectView#render进行跳转分析
    redirect跳转https变为http问题的深入思考_第6张图片
    3.1 下图显示以是否兼容http1.0(http10Compatible) 进行区分获取Location
    (1)默认是兼容http1.0,故response.sendRedirect(encodedURL);
    redirect跳转https变为http问题的深入思考_第7张图片
    (2)response.sendRedirect(encodedURL)最终会触发到tomcat的org.apache.catalina.connector.Response的sendRedirect方法
    redirect跳转https变为http问题的深入思考_第8张图片

    public void sendRedirect(String location, int status) throws IOException {
    	locationUri = toAbsolute(location);
    	setStatus(status);
        setHeader("Location", locationUri); //设置跳转的location
    }
    

    3.2 跳转Location生成的入口:org.apache.catalina.connector.Response#toAbsolute

    // 从request中获取协议、IP、端口信息,然后和设置的相对路径拼接起来
    protected String toAbsolute(String location) {
    	String scheme = request.getScheme();
        String name = request.getServerName();
        int port = request.getServerPort();
        redirectURLCC.append(scheme, 0, scheme.length());
        redirectURLCC.append("://", 0, 3);
        redirectURLCC.append(name, 0, name.length());
        if ((scheme.equals("http") && port != 80)
            || (scheme.equals("https") && port != 443)) {
            redirectURLCC.append(':');
            String portS = port + "";
            redirectURLCC.append(portS, 0, portS.length());
        }
        redirectURLCC.append(location, 0, location.length());
    }
    

Request中协议信息在哪生成

redirect跳转https变为http问题的深入思考_第9张图片

  1. 根据调用栈发现,在ConnectionHandler处理连接时,根据SocketEvent进行区别处理
    redirect跳转https变为http问题的深入思考_第10张图片
    redirect跳转https变为http问题的深入思考_第11张图片
  2. 在Http11Processor处理OPEN_READ事件时会对请求进行预处理
    public SocketState service(SocketWrapperBase socketWrapper)
        throws IOException {
    	prepareRequestProtocol();  //设置为http1.1
    	prepareRequest(); //处理协议(http或者https)
    	getAdapter().service(request, response); //调用后面Dispatcher
    }
    
  3. 在prepareRequest判断是否开启SSL,如果开启则为https
    private void prepareRequest() throws IOException {
    	if (protocol.isSSLEnabled()) {
            request.scheme().setString("https");
        }
    }
    

nginx对跳转的设置

  1. nginx官网对跳转描述:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect
  2. 设置在代理服务器响应的“Location” 头字段中更改的文本。
    2.1 假设代理服务器返回头字段 “ Location: http://localhost:8000/two/some/uri/”。该指令proxy_redirect http://localhost:8000/two/ http://frontend/one/; 将此字符串重写为“ Location: http://frontend/one/some/uri/”。
    2.2 在可以正常跳转的nginx上的配置为如下,将http转换成Https
    proxy_set_header    Host   $host;
    proxy_redirect http:// https://;
    
  3. 本地应用SSL配置:https://zhuanlan.zhihu.com/p/31385073
    #https端口号.
    server.port: 443
    #证书的路径.
    server.ssl.key-store: tomcat.keystore
    #证书密码,请修改为您自己证书的密码.
    server.ssl.key-store-password: 123456
    #秘钥库类型
    server.ssl.keyStoreType: PKCS12
    #证书别名
    server.ssl.keyAlias: tomcat
    

你可能感兴趣的:(spring,java,spring)