gRPC-web 如何处理来自 server-side 流的字节数据?
How gRPC-web handles bytes data from server-side streaming?
我想使用 grpc-web 将示例视频文件从后端 grpc 服务传输到浏览器,我根据 official hello world tutorial 做了一些调整。顺便说一句,特使配置没有任何变化。视频文件被分成17块,我在浏览器中可以收到17条消息,但是里面什么都没有,我应该怎么做才能得到数据?
protobuf定义:
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (stream HelloReply);
}
message HelloRequest {}
message HelloReply {
bytes message = 1;
}
server.js:
var PROTO_PATH = __dirname + '/helloworld.proto';
var grpc = require('grpc');
var fs = require('fs');
var protoLoader = require('@grpc/proto-loader');
var packageDefinition = protoLoader.loadSync(
PROTO_PATH,
{keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
var protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
var helloworld = protoDescriptor.helloworld;
function doSayHello(call) {
let count = 0;
let videoDataStream = fs.createReadStream('./sample.mp4');
videoDataStream.on('data',function(chunk){
console.log(chunk);
console.log(++count);
call.write({videoStream: chunk});
// call.write(chunk);
}).on('end',function(){
call.end();
});
}
function getServer() {
var server = new grpc.Server();
server.addService(helloworld.Greeter.service, {
sayHello: doSayHello,
});
return server;
}
if (require.main === module) {
var server = getServer();
server.bind('0.0.0.0:9090', grpc.ServerCredentials.createInsecure());
server.start();
}
exports.getServer = getServer;
client.js:
const {HelloRequest, HelloReply} = require('./helloworld_pb.js');
const {GreeterClient} = require('./helloworld_grpc_web_pb.js');
var client = new GreeterClient('http://localhost:8080');
var request = new HelloRequest();
client.sayHello(request).on('data', function(chunk){
//console.log(chunk.getMessage());
console.log(chunk);
});
无论如何,如果代理有问题,下面是我的envoy.yaml:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: greeter_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.grpc_web
- name: envoy.cors
- name: envoy.router
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
hosts: [{ socket_address: { address: host.docker.internal, port_value: 9090 }}]
服务器端记录的字节数:
浏览器控制台输出以下:
您是否尝试过使用 gRPC(而不是 gRPC Web)客户端进行测试以消除代理问题的可能性?
我不是很熟悉 Node.JS 实现,但是...
不应该是server.addProtoService(...)
吗?
服务器流式传输的消息也是:
message HelloReply {
bytes message = 1;
}
但是你:
call.write({videoStream: chunk});
不应该是:
call.write({message: chunk});
我想使用 grpc-web 将示例视频文件从后端 grpc 服务传输到浏览器,我根据 official hello world tutorial 做了一些调整。顺便说一句,特使配置没有任何变化。视频文件被分成17块,我在浏览器中可以收到17条消息,但是里面什么都没有,我应该怎么做才能得到数据?
protobuf定义:
syntax = "proto3";
package helloworld;
service Greeter {
rpc SayHello (HelloRequest) returns (stream HelloReply);
}
message HelloRequest {}
message HelloReply {
bytes message = 1;
}
server.js:
var PROTO_PATH = __dirname + '/helloworld.proto';
var grpc = require('grpc');
var fs = require('fs');
var protoLoader = require('@grpc/proto-loader');
var packageDefinition = protoLoader.loadSync(
PROTO_PATH,
{keepCase: true,
longs: String,
enums: String,
defaults: true,
oneofs: true
});
var protoDescriptor = grpc.loadPackageDefinition(packageDefinition);
var helloworld = protoDescriptor.helloworld;
function doSayHello(call) {
let count = 0;
let videoDataStream = fs.createReadStream('./sample.mp4');
videoDataStream.on('data',function(chunk){
console.log(chunk);
console.log(++count);
call.write({videoStream: chunk});
// call.write(chunk);
}).on('end',function(){
call.end();
});
}
function getServer() {
var server = new grpc.Server();
server.addService(helloworld.Greeter.service, {
sayHello: doSayHello,
});
return server;
}
if (require.main === module) {
var server = getServer();
server.bind('0.0.0.0:9090', grpc.ServerCredentials.createInsecure());
server.start();
}
exports.getServer = getServer;
client.js:
const {HelloRequest, HelloReply} = require('./helloworld_pb.js');
const {GreeterClient} = require('./helloworld_grpc_web_pb.js');
var client = new GreeterClient('http://localhost:8080');
var request = new HelloRequest();
client.sayHello(request).on('data', function(chunk){
//console.log(chunk.getMessage());
console.log(chunk);
});
无论如何,如果代理有问题,下面是我的envoy.yaml:
admin:
access_log_path: /tmp/admin_access.log
address:
socket_address: { address: 0.0.0.0, port_value: 9901 }
static_resources:
listeners:
- name: listener_0
address:
socket_address: { address: 0.0.0.0, port_value: 8080 }
filter_chains:
- filters:
- name: envoy.http_connection_manager
config:
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: greeter_service
max_grpc_timeout: 0s
cors:
allow_origin_string_match:
- prefix: "*"
allow_methods: GET, PUT, DELETE, POST, OPTIONS
allow_headers: keep-alive,user-agent,cache-control,content-type,content-transfer-encoding,custom-header-1,x-accept-content-transfer-encoding,x-accept-response-streaming,x-user-agent,x-grpc-web,grpc-timeout
max_age: "1728000"
expose_headers: custom-header-1,grpc-status,grpc-message
http_filters:
- name: envoy.grpc_web
- name: envoy.cors
- name: envoy.router
clusters:
- name: greeter_service
connect_timeout: 0.25s
type: logical_dns
http2_protocol_options: {}
lb_policy: round_robin
hosts: [{ socket_address: { address: host.docker.internal, port_value: 9090 }}]
服务器端记录的字节数:
浏览器控制台输出以下:
您是否尝试过使用 gRPC(而不是 gRPC Web)客户端进行测试以消除代理问题的可能性?
我不是很熟悉 Node.JS 实现,但是...
不应该是server.addProtoService(...)
吗?
服务器流式传输的消息也是:
message HelloReply {
bytes message = 1;
}
但是你:
call.write({videoStream: chunk});
不应该是:
call.write({message: chunk});