Связь по gRPC-WEB между Grpc.AspNetCore.Web (C#) и connectrpc/connect-web (JS)

В соответствии с документацией ( https://learn.microsoft.com/ru-ru/aspnet/core/grpc/grpcweb?view=aspnetcore-9.0 ) можно создать на ASP.NET gRPC-сервис, работающий по gPRC-WEB, к которому можно подключаться из WEB-приложения на JS (из браузера) без использования прокси-сервера Envoy.

Я создаю gRPC-сервис на ASP.NET с использованием Grpc.AspNetCore.Web и настраиваю следующим образом:

public static void Main(string[] args)
{
    var builder = WebApplication.CreateBuilder(args);

    // Add services to the container.
    builder.Services.AddGrpc();

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

    var app = builder.Build();

    // Configure the HTTP request pipeline.
    app.UseRouting();
    app.UseGrpcWeb(new GrpcWebOptions { DefaultEnabled = true });
    app.UseCors("AllowAll");
    app.MapGrpcService<MyServiceService>();
    app.Run();
}

Далее на JS создаю клиент с помощью bufbuild/protobuf и connectrpc/connect-web, и с их помощью вызываю свой сервис. Пример создания клиента на JS:

const transport = createConnectTransport({
  baseUrl: "https://localhost:7167",
  useBinaryFormat: false,
})
const client = createClient(Service, transport)

Однако на стороне сервера я получаю следующее сообщение

info: Grpc.AspNetCore.Server.ServerCallHandler[2]
      Request content-type of 'application/json' is not supported.

Если в JS при создании подключения установить useBinaryFormat: true, то ASP.NET выдаст следующее:

info: Grpc.AspNetCore.Server.ServerCallHandler[2]
      Request content-type of 'application/proto' is not supported.

Такое ощущение, что несмотря на использование Grpc.AspNetCore.Web, сервер ждет стандартный gRPC, а не gRPC-WEB. Подскажите пожалуйста, что я упустил?


Ответы (1 шт):

Автор решения: Artem

Отдельная благодарность EvgeniyZ за очень полезный комментарий.

Действительно, при использовании Grpc.AspNetCore.Web сервер уже работает по протоколу gRPC-WEB, и необходимости в прокси-сервере Envoy нет.

Моя ошибка была в том, что при создании клиента я использовал неправильный транспортный протокол. createConnectTransport() создает не gRPC-WEB, а connect - свой собственный внутренний протокол библиотеки connectrpc/connect-web, который удобен в случае если везде используется ее собственная экосистема. Для того чтобы создать протокол gRPC необходимо использовать createGrpcWebTransport().

Дополню еще один не очевидный момент. У меня заработала связка Grpc.AspNetCore.Web с connectrpc/connect-web только при вот таком интересном сочетании параметров:

const transport = createGrpcWebTransport({
  baseUrl: "https://localhost:7167",
  useBinaryFormat: true,
})
const client = createClient(Summator, transport)

let sumargs = create(SumArgsSchema, {
  a: 3,
  b: 7,
})
const response = await client.sum(sumargs)

Клиент формирует сообщение из двух аргументов и отправляет на gRPC-сервис для их суммирования. Все работает только если выставить флаг useBinaryFormat: true при создании клиента, но при этом передавать аргументы в исходном виде без использования функции toBinary(). Возможно кому-то это будет полезно.

→ Ссылка