GRPC-Web 是谷歌的一个web 端产品,正式发布在2018-11-28,git官网
现阶段js 前端支持还比较少不支持http2的协议(git解答),所以必须使用Envoy或 gowebproxy代理访问grpc 的服务(c++/java/nodejs/go)
// Copyright 2015 gRPC authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
}
proto.exe 下载
JavaScript 生成命令
protoc.exe -I=. helloworld.proto --js_out=import_style=commonjs:..\pb_gen
c++ 生成命令
protoc.exe -I=. --cpp_out=..\pb_gen helloworld.proto
Javascript 需要生成的exe的插件git 下载
protoc.exe -I=.\ Situat.proto --js_out=import_style=commonjs:. --plugin=protoc-gen-grpc=protoc-gen-grpc-web.exe --grpc-web_out=import_style=commonjs,mode=grpcwebtext:.
c++ 生成命令
protoc.exe -I=. --grpc_out=..\pb_gen --plugin=protoc-gen-grpc=grpc_cpp_plugin.exe helloworld.proto
需要nmp 生成编译,package.json
主要的依赖库protobuf和grpc的版本与服务端一定要保持一致
{
"name": "grpc-web-simple-example",
"version": "0.1.0",
"description": "gRPC-Web simple example",
"devDependencies": {
"@grpc/proto-loader": "^0.3.0",
"async": "^1.5.2",
"google-protobuf": "^3.6.1",
"grpc": "^1.17.0",
"grpc-web": "^1.0.3",
"lodash": "^4.6.1",
"webpack": "^4.16.5",
"webpack-cli": "^3.1.0",
"webpack-dev-server": "^3.1.14"
}
}
执行命令
npm install
webpack 打包配置
module.exports = {
entry:
"./client.js",
output:{filename:"./main.js"},
devtool:'source-map'
}
webpack 打包编译
npx webpack
webpack-dev-server 可以测试运行
npx webpack-dev-server
Envoy主要是转发服务,只在liunx 下运行成功了
Envoy 的配置文件,
配置文件中的注释要去掉
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:
# grpc 经过docker 转发的端口
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:
- "*"
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
enabled: true
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
# grpc 的服务端口
hosts: [{ socket_address: { address: localhost, port_value: 9090 }}]
编译文件
$ docker build -t helloworld/envoy -f ./envoy.Dockerfile .
$ docker run -d -p 8080:8080 --network=host helloworld/envoy
说明见gith网址
执行命令
./grpcwebproxy --backend_addr=192.168.0.17:50051 --run_tls_server=FALSE --server_http_debug_port=8892 --allow_all_origins=true --use_websockets=true --server_http_max_read_timeout=50s --server_http_max_write_timeout=50s
参数名 | 值 | 说明 |
---|---|---|
backend_addr | 192.168.0.17:50051 | 要转发的服务ip和端口 |
run_tls_server | true 或false | 默认为true 是否开启tls_server |
server_http_debug_port | 8080 | 转发的新的端口 |
allow_all_origins | true 或false | 默认false,http 是否允许跨域请求 |
use_websockets | true 或false | 默认false 是否启用websockets |
server_http_max_read_timeout | 10s | http 服务读取连接超时 |
server_http_max_write_timeout | 10s | http 服务连接读取超时时间 |
backend_max_call_recv_msg_size | 4 * 1024 * 1024 | 传输消息最大内容限制,默认4Mb |
// 请求服务参数
var unaryRequest = new this.ctors.EchoRequest();
unaryRequest.setMessage(msg);
/** echoAbort 服务接口方法
*unaryRequest 发送数据
*param {} 可以不填写
*param callback 服务返回数据回调函数
*/
this.echoService.echoAbort(unaryRequest, {}, function(err, response) {
if (err) {
echoapp.EchoApp.addRightMessage('Error code: '+err.code+' "'+
err.message+'"');
}
});
-双向流的方式
var streamRequest = new this.ctors.ServerStreamingEchoRequest();
streamRequest.setMessage(msg);
streamRequest.setMessageCount(count);
streamRequest.setMessageInterval(echoapp.EchoApp.INTERVAL);
var stream = this.echoService.serverStreamingEcho(
streamRequest,
{"custom-header-1": "value1"});
var self = this;
//接收服务发送的数据
stream.on('data', function(response) {
echoapp.EchoApp.addRightMessage(response.getMessage());
});
//当前状态
stream.on('status', function(status) {
self.handlers.checkGrpcStatusCode(status);
if (status.metadata) {
console.log("Received metadata");
console.log(status.metadata);
}
});
//错误信息
stream.on('error', function(err) {
echoapp.EchoApp.addRightMessage('Error code: '+err.code+' "'+
err.message+'"');
});
//连接断开
stream.on('end', function() {
console.log("stream end signal received");
});