Kestrel 在处理流量时抛出 "Invalid Host header" 错误
Kestrel throwing "Invalid Host header" error while serving traffic
我们最近将 ASP.NET MVC 5 应用程序迁移到了 ASP.NET Core 2.2。
一切似乎都运行良好,但我们经常收到以下异常(大约每秒 3 次,稍后会详细介绍):
BadHttpRequestException: Invalid Host header: '~^appname.*$'
Module "Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException", line 0, col 0, in Throw
Void Throw(Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.RequestRejectionReason, System.String)
Module "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection", line 95, col 0, in EnsureHostHeaderExists
Void EnsureHostHeaderExists()
Module "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection", line 196, col 0, in TryParseRequest
Boolean TryParseRequest(System.IO.Pipelines.ReadResult, Boolean ByRef)
Module "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequests>d__185`1", line 170, col 0, in MoveNext
Void MoveNext()
Module "System.Runtime.ExceptionServices.ExceptionDispatchInfo", line 12, col 0, in Throw
Void Throw()
Module "System.Runtime.CompilerServices.TaskAwaiter", line 46, col 0, in HandleNonSuccessAndDebuggerNotification
Void HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
Module "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequestsAsync>d__184`1", line 135, col 0, in MoveNext
Void MoveNext()
在咨询我们的运营团队成员后,很明显我们有三个 HAProxy 实例,它们大约每秒检查一次我们应用程序的每个节点。
对该应用程序的每个请求都将按如下方式流动:
HAProxy -> Nginx -> Kestrel/ASP.NET Core 应用程序
我的问题是,我怎样才能确定这里发生了什么?
我猜你应该向那里传递一些有效的 Url、星号或正斜杠
public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
{
Debug.Assert(target.Length != 0, "Request target must be non-zero length");
var ch = target[0];
if (ch == ByteForwardSlash)
{
// origin-form.
// The most common form of request-target.
// https://tools.ietf.org/html/rfc7230#section-5.3.1
OnOriginFormTarget(method, version, target, path, query, customMethod, pathEncoded);
}
else if (ch == ByteAsterisk && target.Length == 1)
{
OnAsteriskFormTarget(method);
}
else if (target.GetKnownHttpScheme(out var scheme))
{
OnAbsoluteFormTarget(target, query);
}
else
{
// Assume anything else is considered authority form.
// FYI: this should be an edge case. This should only happen when
// a client mistakenly thinks this server is a proxy server.
OnAuthorityFormTarget(method, target);
}
Method = method != HttpMethod.Custom
? HttpUtilities.MethodToString(method) ?? string.Empty
: customMethod.GetAsciiStringNonNullCharacters();
_httpVersion = version;
Debug.Assert(RawTarget != null, "RawTarget was not set");
Debug.Assert(Method != null, "Method was not set");
Debug.Assert(Path != null, "Path was not set");
Debug.Assert(QueryString != null, "QueryString was not set");
Debug.Assert(HttpVersion != null, "HttpVersion was not set");
}
例如,我们在 Host header 中发送 LoadBalancer 的主机,如 dc-lb.company-dc.lan,在你的场景中我猜它应该是你的 HAProxy 实例的主机名
当前版本的 Kestrel(我们使用 ASP.NET Core 2.2)不支持 HTTP 访问日志记录。
看到这个问题:Support access logging with Common Log Format/Extended Log Format
为了追查问题,我不得不让我们的运营团队查看我们的 nginx 日志(nginx 是我们正在使用的反向代理)以确定无效主机 header 的请求来自何处.
问题原来是 mal-configured 状态检查应用程序。
我们最近将 ASP.NET MVC 5 应用程序迁移到了 ASP.NET Core 2.2。
一切似乎都运行良好,但我们经常收到以下异常(大约每秒 3 次,稍后会详细介绍):
BadHttpRequestException: Invalid Host header: '~^appname.*$'
Module "Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException", line 0, col 0, in Throw
Void Throw(Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.RequestRejectionReason, System.String)
Module "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection", line 95, col 0, in EnsureHostHeaderExists
Void EnsureHostHeaderExists()
Module "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Http1Connection", line 196, col 0, in TryParseRequest
Boolean TryParseRequest(System.IO.Pipelines.ReadResult, Boolean ByRef)
Module "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequests>d__185`1", line 170, col 0, in MoveNext
Void MoveNext()
Module "System.Runtime.ExceptionServices.ExceptionDispatchInfo", line 12, col 0, in Throw
Void Throw()
Module "System.Runtime.CompilerServices.TaskAwaiter", line 46, col 0, in HandleNonSuccessAndDebuggerNotification
Void HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
Module "Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.HttpProtocol+<ProcessRequestsAsync>d__184`1", line 135, col 0, in MoveNext
Void MoveNext()
在咨询我们的运营团队成员后,很明显我们有三个 HAProxy 实例,它们大约每秒检查一次我们应用程序的每个节点。
对该应用程序的每个请求都将按如下方式流动:
HAProxy -> Nginx -> Kestrel/ASP.NET Core 应用程序
我的问题是,我怎样才能确定这里发生了什么?
我猜你应该向那里传递一些有效的 Url、星号或正斜杠
public void OnStartLine(HttpMethod method, HttpVersion version, Span<byte> target, Span<byte> path, Span<byte> query, Span<byte> customMethod, bool pathEncoded)
{
Debug.Assert(target.Length != 0, "Request target must be non-zero length");
var ch = target[0];
if (ch == ByteForwardSlash)
{
// origin-form.
// The most common form of request-target.
// https://tools.ietf.org/html/rfc7230#section-5.3.1
OnOriginFormTarget(method, version, target, path, query, customMethod, pathEncoded);
}
else if (ch == ByteAsterisk && target.Length == 1)
{
OnAsteriskFormTarget(method);
}
else if (target.GetKnownHttpScheme(out var scheme))
{
OnAbsoluteFormTarget(target, query);
}
else
{
// Assume anything else is considered authority form.
// FYI: this should be an edge case. This should only happen when
// a client mistakenly thinks this server is a proxy server.
OnAuthorityFormTarget(method, target);
}
Method = method != HttpMethod.Custom
? HttpUtilities.MethodToString(method) ?? string.Empty
: customMethod.GetAsciiStringNonNullCharacters();
_httpVersion = version;
Debug.Assert(RawTarget != null, "RawTarget was not set");
Debug.Assert(Method != null, "Method was not set");
Debug.Assert(Path != null, "Path was not set");
Debug.Assert(QueryString != null, "QueryString was not set");
Debug.Assert(HttpVersion != null, "HttpVersion was not set");
}
例如,我们在 Host header 中发送 LoadBalancer 的主机,如 dc-lb.company-dc.lan,在你的场景中我猜它应该是你的 HAProxy 实例的主机名
当前版本的 Kestrel(我们使用 ASP.NET Core 2.2)不支持 HTTP 访问日志记录。
看到这个问题:Support access logging with Common Log Format/Extended Log Format
为了追查问题,我不得不让我们的运营团队查看我们的 nginx 日志(nginx 是我们正在使用的反向代理)以确定无效主机 header 的请求来自何处.
问题原来是 mal-configured 状态检查应用程序。