背景
服务部署以及跳转展示如下:
用户https请求通过阿里云负载通过http到指定应用,应用返回跳转路径(状态为302),但跳转路径为http(不为https),所以访问不了
2.1 跳转伪代码:
// ModelAndView
mv.setViewName(WebCst.REDIRECT + "/admin/sso/login");
1
2
2.2 浏览器跳转截图
结论总结
用nginx负载返回给浏览器的Location为https是因为nginx做了处理,关键配置见下
proxy_set_header Host $host;
proxy_redirect http:// https://;
1
2
1.1 用arthas的trace命令观察线上,应用直接返回的Location为http://localhost:8232/exp-admin/admin/sso/login
watch org.apache.catalina.connector.Response toAbsolute -x 2
1
将nginx替换成SLB后,返回给浏览器的Loaction变为http是因为SLB缺少相应的配置
2.1 SLB相关配置:https://help.aliyun.com/document_detail/97646.html
跳转的Location是如何生成的
后台是以springboot进行开发的,下面的分析都是基于springboot方式进行
先展示一下springmvc的工作原理
2.1 我们跳转设置为:mv.setViewName(WebCst.REDIRECT + “/admin/sso/login”); 结合上图,猜测根据视图进行跳转
2.2 视图解析器ContentNegotiatingViewResolver通过resolveViewName解析视图,得到跳转视图:RedirectView,调用其render进行跳转
以RedirectView#render进行跳转分析
3.1 下图显示以是否兼容http1.0(http10Compatible) 进行区分获取Location
(1)默认是兼容http1.0,故response.sendRedirect(encodedURL);
(2)response.sendRedirect(encodedURL)最终会触发到tomcat的org.apache.catalina.connector.Response的sendRedirect方法
public void sendRedirect(String location, int status) throws IOException {
locationUri = toAbsolute(location);
setStatus(status);
setHeader("Location", locationUri); //设置跳转的location
}
1
2
3
4
5
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());
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Request中协议信息在哪生成
根据调用栈发现,在ConnectionHandler处理连接时,根据SocketEvent进行区别处理
在Http11Processor处理OPEN_READ事件时会对请求进行预处理
public SocketState service(SocketWrapperBase<?> socketWrapper)
throws IOException {
prepareRequestProtocol(); //设置为http1.1
prepareRequest(); //处理协议(http或者https)
getAdapter().service(request, response); //调用后面Dispatcher
}
在prepareRequest判断是否开启SSL,如果开启则为https
private void prepareRequest() throws IOException {
if (protocol.isSSLEnabled()) {
request.scheme().setString("https");
}
}
nginx对跳转的设置
nginx官网对跳转描述:https://nginx.org/en/docs/http/ngx_http_proxy_module.html#proxy_redirect
设置在代理服务器响应的“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://;
本地应用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
转自
redirect跳转https变为http问题的深入思考-CSDN博客
https://blog.csdn.net/weixin_40803011/article/details/121560609