asp.net core中负载均衡场景下http重定向https的问题
上周欣喜地发现,微软官方终于针对 asp.net core 在使用负载均衡的情况下从 http 强制重定向至 https 的问题提供了解决方法。
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto
}); var options = new RewriteOptions()
.AddRedirectToHttpsPermanent();
app.UseRewriter(options);
但实际使用之后,欣喜变成了失望 —— 微软对这个问题的认识角度和我们不一样,造成这个方法对我们不适用,不得不继续使用我们的土方法。
为什么会这样?请看下面的分解。
AddRedirectToHttpsPermanent 早就在 BasicMiddleware 的 RedirectToHttpsRule 中实现了,它的逻辑很简单 —— 判断当前请求是否是https,如果不是就进行重定向。
if (!context.HttpContext.Request.IsHttps)
{
//...
}
这个直接了当的判断在使用负载均衡的场景下不仅不会发挥应有的作用,而且会产生致命的副作用 —— 让请求进入重定向死循环(ERR_TOO_MANY_REDIRECTS)。因为不管客户端的请求是 http 还是 https ,负载均衡与后端服务器之间始终是 http(当然你可以用https,但那是吃饱了撑着还浪费粮食)。如果负载均衡不额外提供这个信息,在后端服务器的眼里始终只有 http 没有 https ,http 重定向 https 根本无法实现。
从负载均衡的角度,为了解决这个问题,通常会通过一个另外的专用的请求头抓发这个信息,它的名字叫"X-Forwarded-Proto"。
从 asp.net core 的角度,要解决这个问题,需要弥补 Request.IsHttps 与 X-Forwarded-Proto 之间的鸿沟。于是微软实现了上面的 app.UseForwardedHeaders() ,实际是由 ForwardedHeadersMiddleware 完成这个任务 —— 根据 X-Forwarded-Proto 设置 Scheme(Request.IsHttps 就是基于 Scheme 进行判断的)。
if (checkProto && i < forwardedProto.Length)
{
set.Scheme = forwardedProto[forwardedProto.Length - i - ];
}
到此为止,微软完美地解决了这个问题,RedirectToHttpsRule 不用修改1行代码。
但是在实际使用时,我们发现一个大问题,大到我们必须弃用这个看似完美的解决方法。
微软解决 http to https 问题的思路是这样:只要请求不是 https 的,就强制跳转到 https(这个没问题),其他一概不管,不管这个请求是不是来自负载均衡转发的(这个不够贴心)。
而我们要解决的问题是:只有在负载均衡转发的原始请求是 http 的情况下,才强制跳转至 https 。比如在服务器本机访问,比如来自其他docker容器的访问,如果这也跳转,那每台服务器(或者docker容器)都要部署https证书,多麻烦。
一个是只要不是 https ,就跳转;一个是只有是转发的 http ,才跳转。 就是因为这个对问题理解的差异,我们不得不放弃采用微软的官方解决方法,继续使用我们不太优雅的土方法。
RedirectToProxiedHttpsRule
public class RedirectToProxiedHttpsRule : RedirectToHttpsRule
{
public RedirectToProxiedHttpsRule()
{
base.StatusCode = StatusCodes.Status301MovedPermanently;
base.SSLPort = null;
} public override void ApplyRule(RewriteContext context)
{
var key = "X-Forwarded-Proto";
var request = context.HttpContext.Request;
if (request.Headers.ContainsKey(key))
{
if (request.Headers[key].FirstOrDefault() == "http")
{
base.ApplyRule(context);
}
}
}
}
RewriteOptionsExtensions
public static class RewriteOptionsExtensions
{
public static RewriteOptions AddRedirectForwardedHttpToHttps(this RewriteOptions options)
{
options.Rules.Add(new RedirectToProxiedHttpsRule());
return options;
}
}
在 Startup 中使用
var options = new RewriteOptions()
.AddRedirectForwardedHttpToHttps();
app.UseRewriter(options);
asp.net core中负载均衡场景下http重定向https的问题的更多相关文章
- CephRGW 在多个RGW负载均衡场景下,RGW 大文件并发分片上传功能验证
http://docs.ceph.com/docs/master/radosgw/s3/objectops/#initiate-multi-part-upload 根据分片上传的API描述,因为对同一 ...
- 使用阿里云负载均衡遭遇的http重定向https的问题
昨天解决了在阿里云负载均衡上部署https证书的问题(详见一个空行引起的阿里云负载均衡上部署https证书的问题),并完成了部署,负载均衡的监听配置是这样的: 用户与负载均衡之间走https协议,负载 ...
- ASP.NET Core 中使用负载均衡时获取客户端 IP
在使用负载均衡的情况下,通过 context.Connection.RemoteIpAddress 获取到的是负载均衡的 IP 地址,需要通过 X-Forwarded-For 请求头才能获取到客户端的 ...
- 项目开发中的一些注意事项以及技巧总结 基于Repository模式设计项目架构—你可以参考的项目架构设计 Asp.Net Core中使用RSA加密 EF Core中的多对多映射如何实现? asp.net core下的如何给网站做安全设置 获取服务端https证书 Js异常捕获
项目开发中的一些注意事项以及技巧总结 1.jquery采用ajax向后端请求时,MVC框架并不能返回View的数据,也就是一般我们使用View().PartialView()等,只能返回json以 ...
- ASP.NET Core中显示自定义错误页面
在 ASP.NET Core 中,默认情况下当发生500或404错误时,只返回http状态码,不返回任何内容,页面一片空白. 如果在 Startup.cs 的 Configure() 中加上 app. ...
- ASP.NET Core 中的 Razor 页面介绍
标题:ASP.NET Core 中的 Razor 页面介绍 地址:https://docs.microsoft.com/zh-cn/aspnet/core/razor-pages/index?view ...
- Nginx知多少系列之(六)Linux下.NET Core项目负载均衡
目录 1.前言 2.安装 3.配置文件详解 4.工作原理 5.Linux下托管.NET Core项目 6.Linux下.NET Core项目负载均衡 7.负载均衡策略详解 8.Linux下.NET C ...
- Windows平台分布式架构实践 - 负载均衡(下)
概述 我们在上一篇Windows平台分布式架构实践 - 负载均衡中讨论了Windows平台下通过NLB(Network Load Balancer) 来实现网站的负载均衡,并且通过压力测试演示了它的效 ...
- Windows平台下利用APM来做负载均衡方案 - 负载均衡(下)
概述 我们在上一篇Windows平台分布式架构实践 - 负载均衡中讨论了Windows平台下通过NLB(Network Load Balancer) 来实现网站的负载均衡,并且通过压力测试演示了它的效 ...
随机推荐
- 关于WebService、WebApi的跨域问题
随着移动互联网的发展, 传统营销模式往网站以及移动客户端转移已经成为一种趋势.接触过互联网开发的开发者肯定会很熟悉两种网络服务WebApi.WebService.在使用JavaScript进行数据交互 ...
- Ninja 之路:试炼!求生演习——异步 I/O、http
鸣人火影之路的第一步,就是跟着卡卡西学习基本的忍术,让自己先在忍者的世界里生存下来,so,想要在 node 的世界里游刃有余,必须要掌握异步 I/O.http等核心技能. ok,第一步先学会读懂需求 ...
- python中从文件中读取数据2
#average7.py 文件中有多行,且每行有多个数字用逗号隔开 def main(): fileName = input("What file are numbers in?" ...
- LeetCode5. Longest Palindromic Substring 最长回文子串 4种方法
题目链接:https://leetcode.com/problems/longest-palindromic-substring/ 题意很简单,就是求一个字符串得最长子串,这里的子串指连续的. 本文给 ...
- [笔记]cin、cout与scanf、printf的效率差异对比分析
之前上传UVa227 puzzle时,好不容易AC了,但发现自己用时50(ms),而在VJ上看到人家都是40ms.20ms,于是打开一个20ms的代码查看人家强在哪里.但结果研究了半天感觉差不多,于是 ...
- 面向切面编程(Aop)
AOP中的概念 AOP(Aspect Orient Programming),也就是面向切面编程.可以这样理解,面向对象编程(OOP)是从静态角度考虑程序结构,面向切面编程(AOP)是从动态角度考虑程 ...
- RabbitMQ学习-1补充
1.如果尝试声明一个已经存在的队列会发生什么? 只要参数完全匹配现存的队列的话,Rabbit什么也不做,并返回成功,就好像这个队列已经创建成功. 2.如何检测队列是否存在? 在创建队列的时候设置que ...
- CNPM 遇到use strict的问题
一.问题描述 [root@VM_123_144_centos node01]# cnpm install --save nodemailer /usr/lib/node_modules/cnpm/no ...
- 用java读写ini配置文件
本文转载地址: http://www.blogjava.net/silvernapoleon/archive/2006/08/07/62222.html import java.io.Bu ...
- jar包和war包
Jar (Java archive), 是将实现了某功能的所有类及辅助资源用ZIP压缩形式打包而成的一个文件, 便于代码的管理和重复使用.当使用别人提供的jar时,只需要在classpath环境变量中 ...