簡體   English   中英

GRPC - HTTP/2 服務器在連接上發送了無效數據。 從 .netcore 3.1 升級到 net5 或 net6 時的 HTTP/2 錯誤代碼“PROTOCOL_ERROR”

[英]GRPC - The HTTP/2 server sent invalid data on the connection. HTTP/2 error code 'PROTOCOL_ERROR when upgrading from .netcore 3.1 to net5 or net6

我有一個調用 GRPC 服務的 .netcore3.1 測試項目。
該服務只能通過 HTTP 獲得。 我現在無法更改服務。

當我將項目更新為 .net5-windows 或 .net6-windows(實際上只是 csproj 更改)時,調用失敗並出現以下錯誤:

Grpc.Core.RpcException : Status(StatusCode="Unavailable", Detail="Error started gRPC call. HttpRequestException: 發送請求時出錯。IOException: 請求被中止。 Http2ConnectionException: HTTP/2 服務器發送無效數據連接。HTTP/2 錯誤代碼 'PROTOCOL_ERROR' (0x1).", DebugException="System.Net.Http.HttpRequestException: 發送請求時出錯。---> System.IO.IOException: 請求被中止. ---> System.Net.Http.Http2ConnectionException: HTTP/2 服務器在連接上發送了無效數據。HTTP/2 錯誤代碼 'PROTOCOL_ERROR' (0x1)。在 System.Net.Http.Http2Connection.ThrowProtocolError(Http2ProtocolErrorCode errorCode ) 在 System.Net.Http.Http2Connection.ReadFrameAsync(Boolean initialFrame) 在 System.Net.Http.Http2Connection.ProcessIncomingFramesAsync() --- 內部異常堆棧跟蹤結束 --- 在 System.Net.Http.Http2Connection.ThrowRequestAborted( System.Net.Http.Http2Connection 的異常 innerException) System.Net.Http.Http2Connection.Http2Stream.TryEnsureHeaders() 的 .Http2Stream.CheckResponseBodyState() System.Net.Http.Http2Connection.Http2Stream.ReadResponseHeadersAsync(CancellationToken cancelToken) 的 System.Net.Http.Http2Connection.SendAsync(HttpRequestMessage 請求, Boolean async, CancellationToken cancelToken) --- 內部異常堆棧跟蹤結束 --- 在 System.Net.Http.Http2Connection.SendAsync(HttpRequestMessage request, Boolean async, CancellationToken cancelToken) 在 System.Net.Http.HttpConnectionPool.SendWithVersionDetectionAndRetryAsync(HttpRequestMessage在 Grpc.Net.Client.Web.GrpcWebHandler.SendAsyncCore(HttpRequestMessage 請求,CancellationToken cancelToken) 的 System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage 請求,布爾異步,CancellationToken cancelToken) 的請求,布爾異步,布爾 doRequestAuth,CancellationToken cancelToken)在 System.Net.Http.HttpClient.g__Core|83_0(HttpRequestMessage 請求,Ht tpCompletionOption completionOption, CancellationTokenSource cts, Boolean disposeCts, CancellationTokenSource pendingRequestsCts, CancellationToken originalCancellationToken) at Grpc.Net.Client.Internal.GrpcCall 2.RunCall(HttpRequestMessage request, Nullable 1 timeout)") at..

我查看了一些 SO 問題(例如.Net Core 3.1 gRPC 客戶端與未加密的 HTTP2 連接Grpc.Core.RpcException: 'Status (StatusCode = "Unavailable", Detail = "Error started gRPC call ) 以及 'call不安全服務的故障排除指南https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-5.0#call-insecure-grpc-services-with-net-core-client但是他們沒有幫助。

在初始化客戶端之前,我嘗試了一些設置 AppContext 的選項(即使他們應該申請 netcore3.1),但同樣沒有幫助:

  AppContext.SetSwitch(“System.Net.Http.SocketsHttpHandler.Http2UnencryptedSupport”, true);
  AppContext.SetSwitch(“System.Net.Http.SocketsHttpHandler.Http2Support”, true);

通道初始化如下:

 var baseUri = new Uri(baseUrl);
        HttpMessageHandler httpMessageHandler = new HttpClientHandler();
        if (baseUri.AbsolutePath != "/")
            httpMessageHandler = new SubDirectoryHandler(httpMessageHandler, baseUri.AbsolutePath);
        var handler = new GrpcWebHandler(GrpcWebMode.GrpcWebText, httpMessageHandler);
        _channel = GrpcChannel.ForAddress(baseUrl, new GrpcChannelOptions { HttpClient = new HttpClient(handler) });

在發送請求之前檢查 GRPC 通道顯示請求版本是 1.1(不考慮 AppContext 設置和 TargetFramework):

在此處輸入圖像描述

GRPC 客戶端庫是:

Grpc.Net.Client v. 2.42.0
Grpc.Net.Client.Web v. 2.42.0

發送請求時,服務端在輸出中記錄以下內容:

拋出異常:Microsoft.AspNetCore.Server.Kestrel.Core.dll 中的“Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException”
拋出異常:System.Private.CoreLib.dll 中的“Microsoft.AspNetCore.Server.Kestrel.Core.BadHttpRequestException”“TradingOrchestrationService.exe”(CoreCLR:clrhost):加載“C:\Program Files\dotnet\shared\Microsoft.AspNetCore .App\6.0.5\Microsoft.AspNetCore.WebUtilities.dll'。
拋出異常:Microsoft.AspNetCore.Server.Kestrel.Transport.Sockets.dll 中的“System.Net.Sockets.SocketException”
由於線程退出或應用程序請求,I/O 操作已中止。

我想強調的關鍵是工作行為和非工作行為之間的唯一區別是將入口程序集中的 TargetFramework 版本從 3.1 提高到 5 或 6。

為了完整性和將來的參考,我在 GitHub https://github.com/dotnet/runtime/issues/71906上發布了我從 JamesNK 獲得的回復

使用 HTTP 時,客戶端和服務器必須使用相同的協議。 沒有https,就沒有協商。

Kestrel 配置使用什么協議? HTTP/1.1 還是 HTTP/2? 如果您沒有明確將其配置為僅 HTTP/2,那么它可能是 HTTP/1.1。

GrpcWebHandler 上有一個 HttpVersion 屬性,你可以設置它來明確指定你想要的 HTTP 版本。 您可以嘗試將其設置為新版本(1、1)。

設置此屬性是否有任何其他含義?
當我們遷移服務器以使用 HTTP/2 時,我想它必須被刪除?

是的

你發生了什么事:在 .NET Core 3.x 中,gRPC 客戶端將 gRPC 請求配置為 HTTP/2,但由於你沒有使用 TLS,請求被靜默降級到 HTTP/1.1

這已在 .NET 5+ 中修復,但您依賴於損壞的行為,因此修復破壞了您。

客戶端現在通過 http 發送 HTTP/2,但您的服務器配置為 HTTP/1.1。 這會產生協議錯誤。 GrpcWebHandler.HttpVersion 為您提供了一種覆蓋 HTTP 版本並准確指定您想要的內容的方法(因為 gRPC-Web 可以與兩個 HTTP 版本一起使用)。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM