Kestrel выдает ошибку «Invalid Host header» при обслуживании трафика - PullRequest
5 голосов
/ 14 мая 2019

Недавно мы перенесли приложение ASP.NET MVC 5 в ASP.NET Core 2.2.

Кажется, все работает нормально, однако мы получаем следующее исключение довольно регулярно (примерно три раза в секунду, подробнее об этом чуть позже):

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()

В консультации с членом нашей команды ops становится ясно, что у нас есть три экземпляра HAProxy, каждый из которых проверяет каждый узел нашего приложения примерно раз в секунду.

Каждый запрос к этому приложению будет выглядеть следующим образом:

HAProxy -> Nginx -> Приложение Kestrel / ASP.NET Core

У меня вопрос, как я могу определить, что здесь происходит?

Ответы [ 2 ]

3 голосов
/ 20 мая 2019

Текущая версия Kestrel (мы используем ASP.NET Core 2.2) не поддерживает протоколирование доступа HTTP.

См. Эту проблему: Поддержка доступа к журналу с общим форматом журнала / расширенным форматом журнала

Для того, чтобы отследить проблему, мне нужно было, чтобы наша ops команда проверила наш nginxлоги (nginx - это обратный прокси-сервер, который мы используем), чтобы определить, откуда поступали запросы с недопустимым заголовком хоста.

Проблема оказалась неправильно настроенным приложением проверки состояния.

1 голос
/ 19 мая 2019

Полагаю, вы должны указать там правильный URL, звездочку или косую черту

Код, отвечающий за синтаксический анализ, здесь https://github.com/aspnet/KestrelHttpServer/blob/b8a1c04ffbeee6c60a74766142ff3e2e6779d701/src/Kestrel.Core/Internal/Http/Http1Connection.cs

        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");
        }

Например, мы отправляем в заголовке хоста узел LoadBalancer, например dc-lb.company-dc.lan, в вашем сценарии, я думаю, это должно быть имя хоста вашего экземпляра HAProxy

...