ASP.NET Core gRPC 應用程式中的 gRPC-Web

作者:James Newton-King

瞭解如何使用gRPC-Web通訊協定,設定可從瀏覽器應用程式呼叫的現有 ASP.NET Core gRPC 服務。 gRPC-Web 允許瀏覽器 JavaScript 和 Blazor 應用程式呼叫 gRPC 服務。 您無法從瀏覽器型應用程式呼叫 HTTP/2 gRPC 服務。 ASP.NET Core中裝載的 gRPC 服務可以設定為支援 gRPC-Web 以及 HTTP/2 gRPC。

如需將 gRPC 服務新增至現有 ASP.NET Core應用程式的指示,請參閱將 gRPC 服務新增至 ASP.NET Core應用程式

如需建立 gRPC 專案的指示,請參閱在 ASP.NET Core 中建立 .NET Core gRPC 用戶端和伺服器

ASP.NET Core gRPC-Web 與 Envoy

有兩個選項可用來將 gRPC-Web 新增至 ASP.NET Core應用程式:

  • 在 ASP.NET Core 中支援 gRPC-Web 與 gRPC HTTP/2。 此選項使用套件提供的 Grpc.AspNetCore.Web 中介軟體。
  • 使用 Envoy Proxy 的 gRPC-Web 支援,將 gRPC-Web 轉譯為 gRPC HTTP/2。 接著會將轉譯的呼叫轉送到 ASP.NET Core應用程式。

每個方法都有優缺點。 如果應用程式的環境已經使用 Envoy 做為 Proxy,則也可以使用 Envoy 來提供 gRPC-Web 支援。 對於只需要 ASP.NET Core的 gRPC-Web 基本解決方案, Grpc.AspNetCore.Web 是不錯的選擇。

在 ASP.NET Core 中設定 gRPC-Web

ASP.NET Core中裝載的 gRPC 服務可以設定為支援 gRPC-Web 以及 HTTP/2 gRPC。 gRPC-Web 不需要對服務進行任何變更。 唯一的修改是啟動組態。

若要使用 ASP.NET Core gRPC 服務啟用 gRPC-Web:

  • 新增封裝的 Grpc.AspNetCore.Web 參考。
  • 將 和 EnableGrpcWeb 新增 UseGrpcWebStartup.cs ,將應用程式設定為使用 gRPC-Web:
public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseGrpcWeb(); // Must be added between UseRouting and UseEndpoints

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb();
    });
}

上述程式碼:

  • 在路由之後和端點之前,新增 gRPC-Web 中介軟體 UseGrpcWeb
  • 指定 endpoints.MapGrpcService<GreeterService>() 方法支援 gRPC-Web 與 EnableGrpcWeb

或者,您可以設定 gRPC-Web 中介軟體,讓所有服務預設都支援 gRPC-Web, EnableGrpcWeb 而且不需要。 指定 new GrpcWebOptions { DefaultEnabled = true } 新增中介軟體的時機。

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddGrpc();
    }

    public void Configure(IApplicationBuilder app)
    {
        app.UseRouting();

        app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapGrpcService<GreeterService>();
        });
    }
}

注意

已知問題會導致 gRPC-Web 在 .NET Core 3.x 中 由 HTTP.sys裝載 時失敗。

(grpc/grpc-dotnet #853) 中提供 grpc-web 實驗性與 UseHttpSys () ? (grpc/grpc-dotnet #853) 中提供 gRPC-Web HTTP.sys 運作的因應措施。

gRPC-Web 和 CORS

瀏覽器安全性可防止網頁向不同網域提出要求,而不是提供網頁的網域。 這項限制適用于使用瀏覽器應用程式進行 gRPC-Web 呼叫。 例如,由 https://www.contoso.com 提供的瀏覽器應用程式會遭到封鎖,而無法呼叫裝載于 上的 https://services.contoso.com gRPC-Web 服務。 跨原始來源資源分享 (CORS) 可用來放寬這項限制。

若要允許瀏覽器應用程式進行跨原始來源 gRPC-Web 呼叫,請在ASP.NET Core 中設定 CORS。 使用內建 CORS 支援,並使用 公開 gRPC 特定標頭。 WithExposedHeaders

public void ConfigureServices(IServiceCollection services)
{
    services.AddGrpc();

    services.AddCors(o => o.AddPolicy("AllowAll", builder =>
    {
        builder.AllowAnyOrigin()
               .AllowAnyMethod()
               .AllowAnyHeader()
               .WithExposedHeaders("Grpc-Status", "Grpc-Message", "Grpc-Encoding", "Grpc-Accept-Encoding");
    }));
}

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();

    app.UseGrpcWeb();
    app.UseCors();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapGrpcService<GreeterService>().EnableGrpcWeb()
                                                  .RequireCors("AllowAll");
    });
}

上述程式碼:

  • 呼叫 AddCors 以新增 CORS 服務,並設定公開 gRPC 特定標頭的 CORS 原則。
  • 在路由設定和端點設定之前,呼叫 UseCors 以新增 CORS 中介軟體。
  • 指定 endpoints.MapGrpcService<GreeterService>() 方法支援使用 RequireCors CORS。

gRPC-Web 和串流

傳統 gRPC over HTTP/2 支援用戶端、伺服器和雙向串流。 gRPC-Web 提供有限的串流支援:

  • gRPC-Web 瀏覽器用戶端不支援呼叫用戶端串流和雙向串流方法。
  • gRPC-Web .NET 用戶端不支援透過 HTTP/1.1 呼叫用戶端串流和雙向串流方法。
  • ASP.NET Core裝載于 Azure App 服務 和 IIS 上的 gRPC 服務不支援雙向串流。

使用 gRPC-Web 時,我們只建議使用一元方法和伺服器串流方法。

HTTP 通訊協定

包含在 .NET SDK 中的 ASP.NET Core gRPC 服務範本會建立僅針對 HTTP/2 設定的應用程式。 當應用程式僅支援傳統 gRPC over HTTP/2 時,這是很好的預設值。 不過,gRPC-Web 同時適用于 HTTP/1.1 和 HTTP/2。 某些平臺,例如 UWP 或 Unity,無法使用 HTTP/2。 若要支援所有用戶端應用程式,請將伺服器設定為啟用 HTTP/1.1 和 HTTP/2。

更新 中的 appsettings.json 預設通訊協定:

{
  "Kestrel": {
    "EndpointDefaults": {
      "Protocols": "Http1AndHttp2"
    }
  }
}

或者, 在啟動程式碼中設定 Kestrel 端點

在相同的埠上啟用 HTTP/1.1 和 HTTP/2 需要 TLS 進行通訊協定交涉。 如需詳細資訊,請參閱ASP.NET Core gRPC 通訊協定交涉

從瀏覽器呼叫 gRPC-Web

瀏覽器應用程式可以使用 gRPC-Web 來呼叫 gRPC 服務。 從瀏覽器使用 gRPC-Web 呼叫 gRPC 服務時,有一些需求和限制:

  • 伺服器必須包含支援 gRPC-Web 的組態。
  • 不支援用戶端串流和雙向串流呼叫。 支援伺服器串流。
  • 在不同的網域上呼叫 gRPC 服務需要伺服器上的 CORS 設定。

JavaScript gRPC-Web 用戶端

JavaScript gRPC-Web 用戶端存在。 如需如何從 JavaScript 使用 gRPC-Web 的指示,請參閱 使用 gRPC-Web 撰寫 JavaScript 用戶端程式代碼

使用 .NET gRPC 用戶端設定 gRPC-Web

.NET gRPC 用戶端可以設定為進行 gRPC-Web 呼叫。 這適用于 Blazor WebAssembly 裝載在瀏覽器中的應用程式,而且具有 JavaScript 程式碼的相同 HTTP 限制。 使用 .NET 用戶端呼叫 gRPC-Web 與 HTTP/2 gRPC相同。 唯一的修改是通道的建立方式。

若要使用 gRPC-Web:

var channel = GrpcChannel.ForAddress("https://localhost:5001", new GrpcChannelOptions
    {
        HttpHandler = new GrpcWebHandler(new HttpClientHandler())
    });

var client = new Greeter.GreeterClient(channel);
var response = await client.SayHelloAsync(new HelloRequest { Name = ".NET" });

上述程式碼:

  • 設定通道以使用 gRPC-Web。
  • 建立用戶端並使用通道進行呼叫。

GrpcWebHandler 具有下列組態選項:

  • InnerHandler:發出 gRPC HTTP 要求的基礎 HttpMessageHandler ,例如 HttpClientHandler
  • GrpcWebMode:列舉型別,指定 gRPC HTTP 要求 Content-Typeapplication/grpc-webapplication/grpc-web-text
    • GrpcWebMode.GrpcWeb 會設定傳送內容而不進行編碼。 預設值。
    • GrpcWebMode.GrpcWebText 會設定 base64 編碼的內容。 瀏覽器的伺服器串流呼叫需要 。
  • HttpVersion:用來在基礎 gRPC HTTP 要求上設定 HttpRequestMessage.Version 的 HTTP 通訊協定 Version 。 gRPC-Web 不需要特定版本,而且除非指定,否則不會覆寫預設值。

重要事項

產生的 gRPC 用戶端具有同步和非同步方法來呼叫一元方法。 例如, SayHello 是同步的,而且 SayHelloAsync 是非同步。 在 中 Blazor WebAssembly 一律需要非同步方法。 在應用程式中呼叫同步方法 Blazor WebAssembly 會導致應用程式沒有回應。

搭配 gRPC-Web 使用 gRPC 用戶端處理站

使用 gRPC 用戶端處理站建立與 gRPC-Web相容的 .NET 用戶端:

builder.Services
    .AddGrpcClient<Greet.GreeterClient>(options =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(new HttpClientHandler()));

如需詳細資訊,請參閱 .NET 中的 gRPC 用戶端處理站整合

其他資源