调用服务方法
现在看看如何调用服务方法。注意,所有方法都是异步的:它们使用 events(事件)和 callbacks(回调)来获取结果。
简单 RPC
调用简单 RPC GetFeature
几乎和调用本地异步方法一样简单。
var point = {latitude: 409146138, longitude: -746188906};
stub.getFeature(point, function(err, feature) {
if (err) {
// process error
} else {
// process feature
}
});
如你所见,我们创建并填充了一个请求对象。最后,我们调用 stub 上的方法,将请求和回调传递给它。如果没有错误,我们j就可以从响应对象中读取服务器的响应信息。
console.log('Found feature called "' + feature.name + '" at ' +
feature.location.latitude/COORD_FACTOR + ', ' +
feature.location.longitude/COORD_FACTOR);
服务端流式 RPC
现在让我们来看看流式方法。如果你已经阅读了创建 server 部分,其中一些可能看起来非常相似。流式 RPC 在两端都以类似的方式实现。
以下调用服务端流式方法 ListFeatures
的代码,它返回地理信息 Feature
的流:
var call = client.listFeatures(rectangle);
call.on('data', function(feature) {
console.log('Found feature called "' + feature.name + '" at ' +
feature.location.latitude/COORD_FACTOR + ', ' +
feature.location.longitude/COORD_FACTOR);
});
call.on('end', function() {
// server 已经完成发送
});
call.on('error', function(e) {
// 出现错误,流被关闭
});
call.on('status', function(status) {
// 处理结果状态
});
与前文传递请求和回调函数给方法不同,我们传递了一个请求并收到一个 Readable
(可读)流对象作为返回。客户端可以使用 Readable
的 'data'
事件来读取服务器的响应。每次收到一个 Feature
消息对象时,该事件都会触发,直到没有更多的消息为止。
在 'data'
回调中的错误不会导致流被关闭。'error'
事件表示发生了错误并且流已关闭。'end'
事件表示服务器已完成发送且没有错误发生。'error'
或 'end'
二者中只会触发一个。最后,当服务器发送状态时,'status'
事件会被触发。
客户端流式 RPC
客户端流式方法 RecordRoute
与服务器端方法类似,不同之处在于我们传递了回调函数并获得了一个 Writable
流。
var call = client.recordRoute(function(error, stats) {
if (error) {
callback(error);
}
console.log('Finished trip with', stats.point_count, 'points');
console.log('Passed', stats.feature_count, 'features');
console.log('Travelled', stats.distance, 'meters');
console.log('It took', stats.elapsed_time, 'seconds');
});
function pointSender(lat, lng) {
return function(callback) {
console.log('Visiting point ' + lat/COORD_FACTOR + ', ' +
lng/COORD_FACTOR);
call.write({
latitude: lat,
longitude: lng
});
_.delay(callback, _.random(500, 1500));
};
}
var point_senders = [];
for (var i = 0; i < num_points; i++) {
var rand_point = feature_list[_.random(0, feature_list.length - 1)];
point_senders[i] = pointSender(rand_point.location.latitude,
rand_point.location.longitude);
}
async.series(point_senders, function() {
call.end();
});
一旦我们使用 write()
将客户端的请求都写入流中,我们需要调用 end()
来告诉 gRPC 我们已经完成了写入。如果结果状态是 OK
,那么 stats
对象就会被服务端的响应正确填充。
双向流式 RPC
最后,让我们看看双向流式 RPC routeChat()
。我们直接调用 routeChat()
并获得一个 Duplex
流对象。它可以用于写入和读取消息。
var call = client.routeChat();
call.on('data', function(note) {
// ...
});
call.on('end', callback);
...
for (var i = 0; i < notes.length; i++) {
var note = notes[i];
call.write(note);
}
call.end();
这里的读取和写入语法与客户端、服务端流式方法非常相似,尽管两端始终按照其写入顺序收到另一方的消息,但是客户端和服务端都可以按任意顺序读取和写入 - 各自的流完全独立运行。