Связь по 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 шт):
Отдельная благодарность 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(). Возможно кому-то это будет полезно.