gRPC服务器返回了空对象

5

基本上,无论我做什么,从我的gRPC服务器回调中返回的JSON对象都是空的。

大部分时间我都在按照这个教程进行操作,只是我使用的是SQLite3服务器而不是knex,并且我已经处理了listProducts方法。 我还没有尝试处理其他产品方法。


server.js中,我从SQLite3数据库获取一些数据,并尝试在回调中返回它。 我还打印出来自数据库的数据以确认我确实获得了有效数据。

gRPC server.js

function listProducts(call, callback) {
  console.log("******** Listed the products *********");
  var data = "";

  let db = new sqlite3.Database('../data/testDB.db', sqlite3.OPEN_READONLY, (err) => {
    if(err){
    console.error(err.message);
    }
    console.log("connected to DB");
  });

  db.serialize(() => {
    db.get('SELECT NAME as name FROM PEEPS', (err, row) => {
          if(err){
            console.error(err.message);
          }
          console.log(row.name);
          data.name = row.name;
    });
  });

  db.close((err) => {
    if(err) {
      console.error(err.message);
    }
    console.log('closed db');
  });

  callback(null, { products:  data.name });
}

来自 gRPC server.js 的输出

******** Listed the products *********
connected to DB
Jeff            // Correct data from DB. 
closed db

回调函数返回到调用它的client.js。然而,该对象始终为空。

如果取消注释res.json({ name: "jessie" });并注释掉res.json(result);,则代码将按预期工作;name: jessie将作为JSON对象发送到浏览器。

因此,这告诉我从客户端到浏览器数据被正确处理了。因此,问题出现在从server.js传递数据到client.js时。

gRPC client.js

// requirements
const path = require('path');
const protoLoader = require('@grpc/proto-loader');
const grpc = require('grpc');

// gRPC client
const productProtoPath = path.join(__dirname, '..', '..', 'protos', 'product.proto');
const productProtoDefinition = protoLoader.loadSync(productProtoPath);
const productPackageDefinition = grpc.loadPackageDefinition(productProtoDefinition).product;
const client = new productPackageDefinition.ProductService('localhost:50051', grpc.credentials.createInsecure());

// handlers
const listProducts = (req, res) => {
  client.listProducts({}, (err, result) => {
      console.log(result);
      console.log(typeof result);
      // console.log(res.json(result));
      res.json(result);
      // res.json({ name: "jessie" });
      console.log("*******************");
  });
};
Server listing on port 3000
{}                 //Oh no! An empty JSON object!
object
*******************

编辑 这里是我的仓库链接:https://github.com/burke212/grpc-node


在你的服务器代码中,看起来你正在将 data 设置为空字符串,然后将 data.name 传递给回调函数。同时你还在其中启动了一些异步操作,但是你没有等待它们完成,因此它们对传递给回调函数的结果没有任何影响。为了理解我的意思,请尝试在调用回调函数之前或之后添加一个 console.log - murgatroid99
@murgatroid99 感谢您指出空数据字符串。我之前尝试过在回调之前和之后使用console.logging,但是两者都得到了相同的结果; undefined。也许这是因为提升?无论如何,我已经缩小了引起最大问题的代码行; client.listProducts(...)。由于它是异步的,所以来自我的index.js中fetch的父调用返回一个Promise {<state>: "pending"}。因此,这使我相信我需要使client.listProducts()成为同步。我走对了吗? - Adonis
你尝试设置环境变量 GRPC_VERBOSITY=DEBUG 了吗?我尝试过了,但是到目前为止没有成功。 - Yandry Pozo
1个回答

0
主要问题在于您的服务器代码中,您的db方法是异步的,但您正在尝试同步访问结果。您需要在db.get的回调函数中调用listProducts的主回调函数,以确保在尝试使用它之前获得该数据库请求的结果。在进行此更改后,您的listProducts方法实现应该看起来更像这样:
function listProducts(call, callback) {

  let db = new sqlite3.Database('../data/testDB.db', sqlite3.OPEN_READONLY);

  db.serialize(() => {
    db.get('SELECT NAME as name FROM PEEPS', (err, row) => {
          if(err){
            console.error(err.message);
          }
          // Call the callback here to use the result of db.get
          callback(null, { products:  row.name });
    });
  });

  db.close();

}

为简单起见,我省略了日志记录。此外,在sqlite3的README示例中,sqlite3.Database构造函数和db.close没有回调函数。建议再次检查这些函数是否实际上需要回调。

除此之外,现在您已经共享了定义服务的product.proto文件,还有另一个问题。在ProductService服务中,listProducts方法声明返回一个ProductList对象。在该消息类型中,products字段必须是Product对象的数组。您方法实现中的所有代码都指向在该字段中返回字符串,这不会导致兼容的对象。


不幸的是,将主回调函数放在db.get()内部也无法解决问题。为了进一步分解问题,我已经用以下代码替换了listProducts()的主体:`let data = { products: "jeff" }; console.log(data); callback(null, data);`只是为了看看server.js是否会返回硬编码对象。然而,client.js返回一个undefined值。因此,问题出在gRPC上?我没有正确设置我的.proto文件吗? - Adonis
如果您在问题中包含了.proto文件,那么将有助于看到另一个问题。您应该在编辑中添加它。您的listProducts方法被声明为返回一个ProductList对象,但是您编写的代码似乎返回了一个ProductName对象。 - murgatroid99

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接