在瀏覽器應用程式中使用 gRPCUse gRPC in browser apps

James 牛頓By James Newton-King

瞭解如何使用 GRPC Web 通訊協定,將現有的 ASP.NET Core gRPC 服務設定為可從瀏覽器應用程式呼叫。Learn how to configure an existing ASP.NET Core gRPC service to be callable from browser apps, using the gRPC-Web protocol. gRPC Web 可讓瀏覽器 JavaScript 和 Blazor 應用程式呼叫 gRPC services。gRPC-Web allows browser JavaScript and Blazor apps to call gRPC services. 您無法從瀏覽器型應用程式呼叫 HTTP/2 gRPC 服務。It's not possible to call an HTTP/2 gRPC service from a browser-based app. ASP.NET Core 中裝載的 gRPC 服務可以設定為支援 gRPC Web 和 HTTP/2 gRPC。gRPC services hosted in ASP.NET Core can be configured to support gRPC-Web alongside HTTP/2 gRPC.

如需將 gRPC 服務新增至現有 ASP.NET Core 應用程式的指示,請參閱 將 gRPC 服務新增至 ASP.NET Core 應用程式For instructions on adding a gRPC service to an existing ASP.NET Core app, see Add gRPC services to an ASP.NET Core app.

如需建立 gRPC 專案的指示,請參閱 在 ASP.NET Core 中建立 .NET Core gRPC 用戶端與伺服器For instructions on creating a gRPC project, see 在 ASP.NET Core 中建立 .NET Core gRPC 用戶端與伺服器.

gRPC-Web in ASP.NET Core 與 EnvoygRPC-Web in ASP.NET Core vs. Envoy

有兩個選項可讓您選擇如何將 gRPC 新增至 ASP.NET Core 應用程式:There are two choices for how to add gRPC-Web to an ASP.NET Core app:

  • 在 ASP.NET Core 中支援 gRPC-Web 與 gRPC HTTP/2。Support gRPC-Web alongside gRPC HTTP/2 in ASP.NET Core. 此選項會使用封裝所提供的中介軟體 Grpc.AspNetCore.WebThis option uses middleware provided by the Grpc.AspNetCore.Web package.
  • 使用 Envoy proxy 的 gRPC web 支援將 gRPC 轉譯成 gRPC HTTP/2。Use the Envoy proxy's gRPC-Web support to translate gRPC-Web to gRPC HTTP/2. 接著會將已轉譯的呼叫轉送至 ASP.NET Core 應用程式。The translated call is then forwarded onto the ASP.NET Core app.

每種方法都有優缺點。There are pros and cons to each approach. 如果應用程式的環境已經使用 Envoy 作為 proxy,也可以使用 Envoy 來提供 gRPC Web 支援。If an app's environment is already using Envoy as a proxy, it might make sense to also use Envoy to provide gRPC-Web support. 針對僅需要 ASP.NET Core 的 gRPC Web 基本解決方案, Grpc.AspNetCore.Web 是不錯的選擇。For a basic solution for gRPC-Web that only requires ASP.NET Core, Grpc.AspNetCore.Web is a good choice.

在 ASP.NET Core 中設定 gRPC WebConfigure gRPC-Web in ASP.NET Core

ASP.NET Core 中裝載的 gRPC 服務可以設定為支援 gRPC Web 和 HTTP/2 gRPC。gRPC services hosted in ASP.NET Core can be configured to support gRPC-Web alongside HTTP/2 gRPC. gRPC-Web 不需要對服務進行任何變更。gRPC-Web does not require any changes to services. 唯一的修改是啟動設定。The only modification is startup configuration.

若要使用 ASP.NET Core gRPC 服務來啟用 gRPC-Web:To enable gRPC-Web with an ASP.NET Core gRPC service:

  • 將參考新增至 Grpc. AspNetCore. Web 封裝。Add a reference to the Grpc.AspNetCore.Web package.
  • 將應用程式新增至 Startup.cs,以將應用程式設定為使用 gRPC-Web UseGrpcWeb EnableGrpcWebConfigure the app to use gRPC-Web by adding UseGrpcWeb and EnableGrpcWeb to Startup.cs:
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();
    });
}

上述程式碼:The preceding code:

  • 新增 gRPC-Web 中介軟體、 UseGrpcWeb 路由之後和端點之前。Adds the gRPC-Web middleware, UseGrpcWeb, after routing and before endpoints.
  • 指定 endpoints.MapGrpcService<GreeterService>() 方法支援 GRPC Web with EnableGrpcWebSpecifies the endpoints.MapGrpcService<GreeterService>() method supports gRPC-Web with EnableGrpcWeb.

或者,您可以設定 gRPC Web 中介軟體,讓所有服務預設都支援 gRPC-Web,而 EnableGrpcWeb 不需要。Alternatively, the gRPC-Web middleware can be configured so all services support gRPC-Web by default and EnableGrpcWeb isn't required. 指定 new GrpcWebOptions { DefaultEnabled = true } 加入中介軟體的時間。Specify new GrpcWebOptions { DefaultEnabled = true } when the middleware is added.

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 在 .NET Core 3.x 中 由 Http.sys 裝載時失敗。There is a known issue that causes gRPC-Web to fail when hosted by Http.sys in .NET Core 3.x.

您可以從 這裡取得 Http.sys 的 gRPC Web 工作使用方法。A workaround to get gRPC-Web working on Http.sys is available here.

gRPC-Web 和 CORSgRPC-Web and CORS

瀏覽器安全性可防止網頁提出要求,而不是與提供網頁的不同網域。Browser security prevents a web page from making requests to a different domain than the one that served the web page. 這種限制適用于使用瀏覽器應用程式進行 gRPC 對 Web 的呼叫。This restriction applies to making gRPC-Web calls with browser apps. 例如,由所提供的瀏覽器應用程式被 https://www.contoso.com 封鎖,無法呼叫裝載于的 GRPC Web 服務 https://services.contoso.comFor example, a browser app served by https://www.contoso.com is blocked from calling gRPC-Web services hosted on https://services.contoso.com. 跨原始資源分享 (CORS) 可用於放寬這種限制。Cross Origin Resource Sharing (CORS) can be used to relax this restriction.

若要允許瀏覽器應用程式進行跨原始 gRPC Web 呼叫,請 在 ASP.NET Core 中設定 CORSTo allow a browser app to make cross-origin gRPC-Web calls, set up CORS in ASP.NET Core. 使用內建 CORS 支援,並使用來公開 gRPC 特定的標頭 WithExposedHeadersUse the built-in CORS support, and expose gRPC-specific headers with 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");
    });
}

上述程式碼:The preceding code:

  • 呼叫 AddCors 以新增 cors 服務,並設定可公開 gRPC 特定標頭的 cors 原則。Calls AddCors to add CORS services and configures a CORS policy that exposes gRPC-specific headers.
  • UseCors在路由之後和端點之前新增 CORS 中介軟體的呼叫。Calls UseCors to add the CORS middleware after routing and before endpoints.
  • 指定 endpoints.MapGrpcService<GreeterService>() 使用支援 CORS 的方法 RequiresCorsSpecifies the endpoints.MapGrpcService<GreeterService>() method supports CORS with RequiresCors.

gRPC-Web 和串流gRPC-Web and streaming

傳統的 gRPC over HTTP/2 支援所有方向的串流。Traditional gRPC over HTTP/2 supports streaming in all directions. gRPC-Web 提供有限的串流支援:gRPC-Web offers limited support for streaming:

  • gRPC-網頁瀏覽器用戶端不支援呼叫用戶端串流和雙向串流方法。gRPC-Web browser clients don't support calling client streaming and bidirectional streaming methods.
  • ASP.NET Core 裝載于 Azure App Service 上的 gRPC 服務,而且 IIS 不支援雙向串流。ASP.NET Core gRPC services hosted on Azure App Service and IIS don't support bidirectional streaming.

使用 gRPC Web 時,我們只建議使用一元方法和伺服器串流方法。When using gRPC-Web, we only recommend the use of unary methods and server streaming methods.

從瀏覽器呼叫 gRPC-WebCall gRPC-Web from the browser

瀏覽器應用程式可以使用 gRPC-Web 來呼叫 gRPC services。Browser apps can use gRPC-Web to call gRPC services. 從瀏覽器呼叫 gRPC 服務與 gRPC 時,有一些需求和限制:There are some requirements and limitations when calling gRPC services with gRPC-Web from the browser:

  • 伺服器必須設定為支援 gRPC Web。The server must have been configured to support gRPC-Web.
  • 不支援用戶端串流和雙向串流呼叫。Client streaming and bidirectional streaming calls aren't supported. 支援伺服器串流。Server streaming is supported.
  • 在不同的網域上呼叫 gRPC 服務需要在伺服器上設定 CORSCalling gRPC services on a different domain requires CORS to be configured on the server.

JavaScript gRPC-Web 用戶端JavaScript gRPC-Web client

有一個 JavaScript gRPC Web 用戶端。There is a JavaScript gRPC-Web client. 如需如何從 JavaScript 使用 gRPC Web 的指示,請參閱 使用 gRPC 撰寫 javascript 用戶端程式代碼For instructions on how to use gRPC-Web from JavaScript, see write JavaScript client code with gRPC-Web.

使用 .NET gRPC 用戶端設定 gRPC-WebConfigure gRPC-Web with the .NET gRPC client

您可以設定 .NET gRPC 用戶端來進行 gRPC Web 呼叫。The .NET gRPC client can be configured to make gRPC-Web calls. 這適用于裝載 Blazor WebAssembly 于瀏覽器中的應用程式,且具有 JavaScript 程式碼的相同 HTTP 限制。This is useful for Blazor WebAssembly apps, which are hosted in the browser and have the same HTTP limitations of JavaScript code. 使用 .NET 用戶端呼叫 gRPC Web 與 HTTP/2 gRPC 相同Calling gRPC-Web with a .NET client is the same as HTTP/2 gRPC. 唯一的修改是通道的建立方式。The only modification is how the channel is created.

若要使用 gRPC-Web:To use gRPC-Web:

  • 將參考新增至 Grpc .net. Web 封裝。Add a reference to the Grpc.Net.Client.Web package.
  • 確定 Grpc .net 的參考是2.29.0 或更高。Ensure the reference to Grpc.Net.Client package is 2.29.0 or greater.
  • 將通道設定為使用 GrpcWebHandlerConfigure the channel to use the GrpcWebHandler:
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" });

上述程式碼:The preceding code:

  • 設定通道以使用 gRPC Web。Configures a channel to use gRPC-Web.
  • 建立用戶端,並使用通道進行呼叫。Creates a client and makes a call using the channel.

GrpcWebHandler 具有下列設定選項:GrpcWebHandler has the following configuration options:

  • InnerHandlerHttpMessageHandler 建立 gRPC HTTP 要求的基礎,例如 HttpClientHandlerInnerHandler: The underlying HttpMessageHandler that makes the gRPC HTTP request, for example, HttpClientHandler.
  • GrpcWebMode:列舉型別,這個型別會指定 gRPC HTTP 要求是否 Content-Typeapplication/grpc-webapplication/grpc-web-textGrpcWebMode: An enumeration type that specifies whether the gRPC HTTP request Content-Type is application/grpc-web or application/grpc-web-text.
    • GrpcWebMode.GrpcWeb 設定要在不編碼的情況下傳送的內容。GrpcWebMode.GrpcWeb configures content to be sent without encoding. 預設值。Default value.
    • GrpcWebMode.GrpcWebText 將內容設定為 base64 編碼。GrpcWebMode.GrpcWebText configures content to be base64 encoded. 在瀏覽器中進行伺服器串流呼叫的必要項。Required for server streaming calls in browsers.
  • HttpVersion: HTTP 通訊協定, Version 用來設定基礎 gRPC Http 要求的 HttpRequestMessage。HttpVersion: HTTP protocol Version used to set HttpRequestMessage.Version on the underlying gRPC HTTP request. gRPC-Web 不需要特定版本,除非已指定,否則不會覆寫預設值。gRPC-Web doesn't require a specific version and doesn't override the default unless specified.

重要

產生的 gRPC 用戶端具有可呼叫一元方法的同步和非同步方法。Generated gRPC clients have sync and async methods for calling unary methods. 例如, SayHello 為 sync 且 SayHelloAsync 為 async。For example, SayHello is sync and SayHelloAsync is async. 在應用程式中呼叫同步方法 Blazor WebAssembly 會導致應用程式沒有回應。Calling a sync method in a Blazor WebAssembly app will cause the app to become unresponsive. 非同步方法必須一律用於中 Blazor WebAssembly 。Async methods must always be used in Blazor WebAssembly.

使用 gRPC client factory 搭配 gRPC-WebUse gRPC client factory with gRPC-Web

您可以使用 gRPC 與 HttpClientFactory的整合來建立 gRPC Web 相容的 .net 用戶端。A gRPC-Web compatible .NET client can be created using gRPC's integration with HttpClientFactory.

若要使用 gRPC-Web 搭配用戶端 factory:To use gRPC-Web with client factory:

  • 將套件參考新增至下列封裝的專案檔:Add package references to the project file for the following packages:
  • 使用泛型擴充方法 (DI) 註冊相依性插入的 gRPC 用戶端 AddGrpcClientRegister a gRPC client with dependency injection (DI) using the generic AddGrpcClient extension method. 在 Blazor WebAssembly 應用程式中,服務是在中向 DI 註冊的 Program.csIn a Blazor WebAssembly app, services are registered with DI in Program.cs.
  • GrpcWebHandler使用 ConfigurePrimaryHttpMessageHandler 擴充方法進行設定。Configure GrpcWebHandler using the ConfigurePrimaryHttpMessageHandler extension method.
builder.Services
    .AddGrpcClient<Greet.GreeterClient>((services, options) =>
    {
        options.Address = new Uri("https://localhost:5001");
    })
    .ConfigurePrimaryHttpMessageHandler(
        () => new GrpcWebHandler(GrpcWebMode.GrpcWebText, new HttpClientHandler()));

如需詳細資訊,請參閱 .NET Core 中的 gRPC 用戶端工廠整合For more information, see .NET Core 中的 gRPC 用戶端工廠整合.

其他資源Additional resources