HTTP/2 с .Net Core и Kestrel

Я пытаюсь настроить веб-сервер с Kestrel в ASP.Net Core 3.1 для поддержки HTTP/2. Вот как я настраиваю Kestrel:

public class Program
{
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args)
        {
            return Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseKestrel(options =>
                {
                    options.ListenLocalhost(8080, listenOptions =>
                    {
                        listenOptions.Protocols = HttpProtocols.Http2;
                    });
                })
                .UseStartup<Startup>();
            });
        }
}

И вот как я проверяю это, отправляя запрос с предварительным HTTP/2 знанием в консольном приложении:

class Program
{
        static async Task Main(string[] args)
        {
            AppContext.SetSwitch("System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport", true);

            using var client = new HttpClient
            {
                BaseAddress = new Uri("http://localhost:8080"),
                DefaultRequestVersion = new Version(2, 0)
            };
            var req = new HttpRequestMessage(HttpMethod.Get, "/");
            var res = await client.SendAsync(req);
            var version = res.Version;
            Console.WriteLine(version);
            Console.ReadKey();
        }
    }
}

К сожалению, вызывающая программа завершается ошибкой с этим исключением IOException: The response ended prematurely:


System.Net.Http.HttpRequestException
  HResult=0x80131620
  Message=An error occurred while sending the request.
  Source=System.Net.Http
  StackTrace:
   at System.Net.Http.HttpConnection.<SendAsyncCore>d__53.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpConnectionPool.<SendWithNtConnectionAuthAsync>d__48.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpConnectionPool.<SendWithRetryAsync>d__47.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.RedirectHandler.<SendAsync>d__4.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at System.Net.Http.HttpClient.<FinishSendAsyncBuffered>d__70.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ConsoleApp17.Program.<Main>d__0.MoveNext() in C:\Users\Hans\source\repos\ConsoleApp17\ConsoleApp17\Program.cs:line 19

  This exception was originally thrown at this call stack:
    System.Net.Http.HttpConnection.FillAsync()
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
    System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(bool)
    System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
    System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)
    System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(System.Threading.Tasks.Task)
    ...
    [Call Stack Truncated]

Inner Exception 1:
IOException: The response ended prematurely.

Что мне здесь не хватает?


person Hans    schedule 07.12.2020    source источник
comment
У вас есть ReadKey в клиенте, но не на сервере. Сервер завершает и удаляет соединение.   -  person jdweng    schedule 07.12.2020
comment
@jdweng Что???! Сервер Kestrel находится внутри приложения ASP.NET Core.   -  person Hans    schedule 07.12.2020
comment
Измените порт на 5001   -  person MichaelMao    schedule 07.12.2020
comment
Что-нибудь работает на localhost:8080? Этот ответ поможет вам?   -  person Akif    schedule 07.12.2020
comment
@Hans: Что мешает завершению кода сервера? Когда приложение закрывается, соединение закрывается.   -  person jdweng    schedule 07.12.2020
comment
@MichaelMao Не повезло!   -  person Hans    schedule 07.12.2020
comment
@Akif Ничего, кроме моего приложения. Я изменил порт на 5001 и все тот же результат   -  person Hans    schedule 07.12.2020


Ответы (1)


похоже, есть проблема - https://github.com/dotnet/aspnetcore/issues/27536#issuecomment-731932924 Пробовал с Http1, работало нормально

listenOptions.Protocols = HttpProtocols.Http1;
person coder_b    schedule 07.12.2020
comment
Это не grpc звонок. Это простой HTTP-запрос - person Hans; 07.12.2020
comment
по умолчанию http2 идет с зашифрованными сообщениями, но есть способ отключить docs.microsoft.com/en-us/dotnet/core/whats-new/ - person coder_b; 07.12.2020
comment
Уже отключен - person Hans; 07.12.2020