Контекст таков, что я работаю над настраиваемым макетом gRPC-сервера, который будет работать в экземпляре Docker и служить макетом серверных служб. Я инициализирую каждый экземпляр с помощью прото-файла и конфигурации, которая сообщает ему, какие функции прослушивать и какими данными отвечать.
Я использую @grpc/grpc-js и @grpc/proto-loader. Я уже настроил его на возврат произвольных скалярных значений, а также массивов и объектов с известной схемой. Все работало, пока я не дошел до той части, где мне хотелось генерировать произвольные объекты (то есть карты). По какой-то причине сервер gRPC не распознает объект, который я ему передаю, как объект и жалуется.
Ошибка, сообщенная клиентом:
Error: 13 INTERNAL: Error serializing response: .Result.testObject: object expected
at callErrorFromStatus (***/test/grpc/node_modules/@grpc/grpc-js/build/src/call.js:31:19)
at Object.onReceiveStatus (***/test/grpc/node_modules/@grpc/grpc-js/build/src/client.js:192:76)
at Object.onReceiveStatus (***/test/grpc/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:360:141)
at Object.onReceiveStatus (***/test/grpc/node_modules/@grpc/grpc-js/build/src/client-interceptors.js:323:181)
at ***/test/grpc/node_modules/@grpc/grpc-js/build/src/resolving-call.js:99:78
at process.processTicksAndRejections (node:internal/process/task_queues:77:11)
for call at
at ServiceClientImpl.makeUnaryRequest (***/test/grpc/node_modules/@grpc/grpc-js/build/src/client.js:160:32)
at ServiceClientImpl.<anonymous> (***/test/grpc/node_modules/@grpc/grpc-js/build/src/make-client.js:105:19)
at file://***/test/grpc/index.mjs:14:10
at file://***/test/grpc/index.mjs:18:3
at ModuleJob.run (node:internal/modules/esm/module_job:217:25)
at async ModuleLoader.import (node:internal/modules/esm/loader:316:24)
at async loadESM (node:internal/process/esm_loader:34:7)
at async handleMainPromise (node:internal/modules/run_main:66:12) {
code: 13,
details: 'Error serializing response: .Result.testObject: object expected',
metadata: Metadata {
internalRepr: Map(2) { 'content-type' => [Array], 'date' => [Array] },
options: {}
}
}
Это мой файл прототипа (одинаковый как для клиента, так и для сервера):
syntax = "proto3";
service TestApi {
rpc Execute(None) returns (Result);
}
message None {}
message Result {
map<string, Value> testObject = 1;
}
message Value {
oneof kind {
bool boolValue = 1;
int32 intValue = 2;
double doubleValue = 3;
string stringValue = 4;
}
}
Функция-обработчик сервера:
export function handler(call, callback) {
try {
const response = generateValues('$', outputs); // Generate random response
console.info(response);
callback(null, response);
} catch (e) {
console.error(e);
callback(e, null);
}
}
console.error никогда не срабатывает. Пример вывода console.info:
{
testObject: {
VmZWD: false,
VXiRwi: 28.087891844342792,
cjCTDFD: false,
inYZS: 6,
AYKahk: ' xsyflf szsnwb ush',
pgUT: 23.19160119367565
}
}
Вещи, которые я пробовал, привели к той же ошибке:
Value на google.protobuf.Any (с соответствующим импортом)json, object и oneOf функции загрузки proto-loader значений true или false.Обратите внимание, что изменить map на другую структуру невозможно, поскольку рабочие прототипы, которые это изображение должно имитировать, уже используют map в своих определениях.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Создаваемый вами объект не соответствует определенным вами типам сообщений. Поле карты testObject имеет тип значения Value, который определяется как сообщение, содержащее одно из нескольких полей. В вашем примере объекта ответа ключ VmZWD имеет значение false, но сообщение Value, представляющее значение false, будет представлено как { boolValue: false }. Все записи карты имеют одну и ту же проблему.
Сообщение Any содержит другое сериализованное сообщение типа, указанного в самом сообщении. Таким образом, это фактически добавит еще один уровень инкапсуляции для каждого значения, и вам нужно будет выполнить еще одну операцию сериализации и десериализации для каждого значения. Просто оберните каждое значение в объект Value, чтобы он соответствовал определению сообщения.
А что, если я установлю тип
Any?