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 不需要對服務進行任何變更。 唯一的修改是在 中 Program.cs設定中間件。

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

  • 將參考新增至 Grpc.AspNetCore.Web 套件。
  • UseGrpcWebEnableGrpcWeb 新增至 Program.cs,將應用程式設定為使用 gRPC-Web:
using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

app.UseGrpcWeb();

app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "This gRPC service is gRPC-Web enabled and is callable from browser apps uisng the gRPC-Web protocal");

app.Run();

上述 程式碼:

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

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

using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

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

app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "All gRPC service are supported by default in this example, and are callable from browser apps uisng the gRPC-Web protocal");

app.Run();

注意

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

Grpc-web experimental and 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 支援,並使用 WithExposedHeaders 公開 gRPC 特定標頭。

using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

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

var app = builder.Build();

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

app.MapGrpcService<GreeterService>().EnableGrpcWeb()
                                    .RequireCors("AllowAll");

app.MapGet("/", () => "This gRPC service is gRPC-Web enabled, CORS enabled, and is callable from browser apps uisng the gRPC-Web protocal");

app.Run();

上述 程式碼:

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

gRPC-Web 和串流

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

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

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

HTTP 通訊協定

包含在 .NET SDK 中的 ASP.NET Core gRPC 服務範本會建立只針對 HTTP/2 設定的應用程式。 當應用程式只支援透過 HTTP/2 的傳統 gRPC 時,這是很好的預設值。 不過,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 呼叫。 這對於裝載於瀏覽器中且 JavaScript 程式碼具有相同 HTTP 限制的 Blazor WebAssembly 應用程式很有用。 使用 .NET 用戶端呼叫 gRPC-Web 與 HTTP/2 gRPC 相同。 唯一的修改是通道的建立方式。

若要使用 gRPC-Web:

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

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

上述 程式碼:

  • 設定通道以使用 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 用戶端 Factory

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

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

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

其他資源

了解如何使用 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 不需要對服務進行任何變更。 唯一的修改是在 中 Program.cs設定 middelware。

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

  • 將參考新增至 Grpc.AspNetCore.Web 套件。
  • UseGrpcWebEnableGrpcWeb 新增至 Program.cs,將應用程式設定為使用 gRPC-Web:
using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

app.UseGrpcWeb();

app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "This gRPC service is gRPC-Web enabled and is callable from browser apps uisng the gRPC-Web protocal");

app.Run();

上述 程式碼:

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

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

using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

var app = builder.Build();

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

app.MapGrpcService<GreeterService>().EnableGrpcWeb();
app.MapGet("/", () => "All gRPC service are supported by default in this example, and are callable from browser apps uisng the gRPC-Web protocal");

app.Run();

注意

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

Grpc-web experimental and 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 支援,並使用 WithExposedHeaders 公開 gRPC 特定標頭。

using GrpcGreeter.Services;

var builder = WebApplication.CreateBuilder(args);

builder.Services.AddGrpc();

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

var app = builder.Build();

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

app.MapGrpcService<GreeterService>().EnableGrpcWeb()
                                    .RequireCors("AllowAll");

app.MapGet("/", () => "This gRPC service is gRPC-Web enabled, CORS enabled, and is callable from browser apps uisng the gRPC-Web protocal");

app.Run();

上述 程式碼:

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

gRPC-Web 和串流

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

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

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

HTTP 通訊協定

包含在 .NET SDK 中的 ASP.NET Core gRPC 服務範本會建立只針對 HTTP/2 設定的應用程式。 當應用程式只支援透過 HTTP/2 的傳統 gRPC 時,這是很好的預設值。 不過,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 呼叫。 這對於裝載於瀏覽器中且 JavaScript 程式碼具有相同 HTTP 限制的 Blazor WebAssembly 應用程式很有用。 使用 .NET 用戶端呼叫 gRPC-Web 與 HTTP/2 gRPC 相同。 唯一的修改是通道的建立方式。

若要使用 gRPC-Web:

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

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

上述 程式碼:

  • 設定通道以使用 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 用戶端 Factory

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

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

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

其他資源

了解如何使用 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 套件。
  • UseGrpcWebEnableGrpcWeb 新增至 Startup.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>() 方法使用 EnableGrpcWeb 支援 gRPC-Web。

或者,您可以設定 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-web experimental and 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 支援,並使用 WithExposedHeaders 公開 gRPC 特定標頭。

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 和串流

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

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

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

HTTP 通訊協定

包含在 .NET SDK 中的 ASP.NET Core gRPC 服務範本會建立只針對 HTTP/2 設定的應用程式。 當應用程式只支援透過 HTTP/2 的傳統 gRPC 時,這是很好的預設值。 不過,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 呼叫。 這對於裝載於瀏覽器中且 JavaScript 程式碼具有相同 HTTP 限制的 Blazor WebAssembly 應用程式很有用。 使用 .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 用戶端 Factory

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

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

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

其他資源