技术标签: grpc-web node.js javascript
从 https://github.com/improbable-eng/grpc-web/releases/tag/v0.13.0 按操作系统选择下载,如:grpcwebproxy-v0.13.0-win64.exe.zip 。
下载完成后把 grpcwebproxy.exe 放到自建的文件夹,并添加到环境变量的path中。
使用grpcwebproxy代理服务,命令为:
示例:grpcwebproxy --allow_all_origins --backend_addr=localhost:50051 --run_tls_server=false --server_http_debug_port=5005
本地实际为:
grpcwebproxy --allow_all_origins --backend_addr=192.168.1.103:8090 --run_tls_server=false --server_http_debug_port=5005
其中用到的参数说明:
使用命令把当前文件夹下面所有的.proto文件转成XXX_pb.js和XXX_grpc_web_pb.js,命令为:
protoc --js_out=import_style=commonjs:. --grpc-web_out=import_style=commonjs,mode=grpcwebtext:. ./*.proto
hello.proto 文件内容为:
syntax = "proto3";
package hello;
option go_package=".;hello";
// 请求参数
message HelloRequest {
string name = 1;
}
// 响应消息
message HelloInfo {
string hello_data = 1;
}
//服务定义
service HelloService {
rpc Hello (HelloRequest) returns (HelloInfo);
}
转成 XXX_pb.js和XXX_grpc_web_pb.js:
/**
* @fileoverview gRPC-Web generated client stub for hello
* @enhanceable
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
/* eslint-disable */
// @ts-nocheck
const grpc = {
};
grpc.web = require('grpc-web');
const proto = {
};
proto.hello = require('./hello_pb.js');
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.hello.HelloServiceClient =
function(hostname, credentials, options) {
if (!options) options = {
};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @param {string} hostname
* @param {?Object} credentials
* @param {?Object} options
* @constructor
* @struct
* @final
*/
proto.hello.HelloServicePromiseClient =
function(hostname, credentials, options) {
if (!options) options = {
};
options['format'] = 'text';
/**
* @private @const {!grpc.web.GrpcWebClientBase} The client
*/
this.client_ = new grpc.web.GrpcWebClientBase(options);
/**
* @private @const {string} The hostname
*/
this.hostname_ = hostname;
};
/**
* @const
* @type {!grpc.web.MethodDescriptor<
* !proto.hello.HelloRequest,
* !proto.hello.HelloInfo>}
*/
const methodDescriptor_HelloService_Hello = new grpc.web.MethodDescriptor(
'/hello.HelloService/Hello',
grpc.web.MethodType.UNARY,
proto.hello.HelloRequest,
proto.hello.HelloInfo,
/**
* @param {!proto.hello.HelloRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.hello.HelloInfo.deserializeBinary
);
/**
* @const
* @type {!grpc.web.AbstractClientBase.MethodInfo<
* !proto.hello.HelloRequest,
* !proto.hello.HelloInfo>}
*/
const methodInfo_HelloService_Hello = new grpc.web.AbstractClientBase.MethodInfo(
proto.hello.HelloInfo,
/**
* @param {!proto.hello.HelloRequest} request
* @return {!Uint8Array}
*/
function(request) {
return request.serializeBinary();
},
proto.hello.HelloInfo.deserializeBinary
);
/**
* @param {!proto.hello.HelloRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @param {function(?grpc.web.Error, ?proto.hello.HelloInfo)}
* callback The callback function(error, response)
* @return {!grpc.web.ClientReadableStream<!proto.hello.HelloInfo>|undefined}
* The XHR Node Readable Stream
*/
proto.hello.HelloServiceClient.prototype.hello =
function(request, metadata, callback) {
return this.client_.rpcCall(this.hostname_ +
'/hello.HelloService/Hello',
request,
metadata || {
},
methodDescriptor_HelloService_Hello,
callback);
};
/**
* @param {!proto.hello.HelloRequest} request The
* request proto
* @param {?Object<string, string>} metadata User defined
* call metadata
* @return {!Promise<!proto.hello.HelloInfo>}
* Promise that resolves to the response
*/
proto.hello.HelloServicePromiseClient.prototype.hello =
function(request, metadata) {
return this.client_.unaryCall(this.hostname_ +
'/hello.HelloService/Hello',
request,
metadata || {
},
methodDescriptor_HelloService_Hello);
};
module.exports = proto.hello;
// source: hello.proto
/**
* @fileoverview
* @enhanceable
* @suppress {missingRequire} reports error on implicit type usages.
* @suppress {messageConventions} JS Compiler reports an error if a variable or
* field starts with 'MSG_' and isn't a translatable message.
* @public
*/
// GENERATED CODE -- DO NOT EDIT!
/* eslint-disable */
// @ts-nocheck
var jspb = require('google-protobuf');
var goog = jspb;
var global = Function('return this')();
goog.exportSymbol('proto.hello.HelloInfo', null, global);
goog.exportSymbol('proto.hello.HelloRequest', null, global);
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.hello.HelloRequest = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.hello.HelloRequest, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.hello.HelloRequest.displayName = 'proto.hello.HelloRequest';
}
/**
* Generated by JsPbCodeGenerator.
* @param {Array=} opt_data Optional initial data array, typically from a
* server response, or constructed directly in Javascript. The array is used
* in place and becomes part of the constructed object. It is not cloned.
* If no data is provided, the constructed object will be empty, but still
* valid.
* @extends {jspb.Message}
* @constructor
*/
proto.hello.HelloInfo = function(opt_data) {
jspb.Message.initialize(this, opt_data, 0, -1, null, null);
};
goog.inherits(proto.hello.HelloInfo, jspb.Message);
if (goog.DEBUG && !COMPILED) {
/**
* @public
* @override
*/
proto.hello.HelloInfo.displayName = 'proto.hello.HelloInfo';
}
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.hello.HelloRequest.prototype.toObject = function(opt_includeInstance) {
return proto.hello.HelloRequest.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.hello.HelloRequest} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.hello.HelloRequest.toObject = function(includeInstance, msg) {
var f, obj = {
name: jspb.Message.getFieldWithDefault(msg, 1, "")
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.hello.HelloRequest}
*/
proto.hello.HelloRequest.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.hello.HelloRequest;
return proto.hello.HelloRequest.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.hello.HelloRequest} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.hello.HelloRequest}
*/
proto.hello.HelloRequest.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setName(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.hello.HelloRequest.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.hello.HelloRequest.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.hello.HelloRequest} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.hello.HelloRequest.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getName();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
};
/**
* optional string name = 1;
* @return {string}
*/
proto.hello.HelloRequest.prototype.getName = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/**
* @param {string} value
* @return {!proto.hello.HelloRequest} returns this
*/
proto.hello.HelloRequest.prototype.setName = function(value) {
return jspb.Message.setProto3StringField(this, 1, value);
};
if (jspb.Message.GENERATE_TO_OBJECT) {
/**
* Creates an object representation of this proto.
* Field names that are reserved in JavaScript and will be renamed to pb_name.
* Optional fields that are not set will be set to undefined.
* To access a reserved field use, foo.pb_<name>, eg, foo.pb_default.
* For the list of reserved names please see:
* net/proto2/compiler/js/internal/generator.cc#kKeyword.
* @param {boolean=} opt_includeInstance Deprecated. whether to include the
* JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @return {!Object}
*/
proto.hello.HelloInfo.prototype.toObject = function(opt_includeInstance) {
return proto.hello.HelloInfo.toObject(opt_includeInstance, this);
};
/**
* Static version of the {@see toObject} method.
* @param {boolean|undefined} includeInstance Deprecated. Whether to include
* the JSPB instance for transitional soy proto support:
* http://goto/soy-param-migration
* @param {!proto.hello.HelloInfo} msg The msg instance to transform.
* @return {!Object}
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.hello.HelloInfo.toObject = function(includeInstance, msg) {
var f, obj = {
helloData: jspb.Message.getFieldWithDefault(msg, 1, "")
};
if (includeInstance) {
obj.$jspbMessageInstance = msg;
}
return obj;
};
}
/**
* Deserializes binary data (in protobuf wire format).
* @param {jspb.ByteSource} bytes The bytes to deserialize.
* @return {!proto.hello.HelloInfo}
*/
proto.hello.HelloInfo.deserializeBinary = function(bytes) {
var reader = new jspb.BinaryReader(bytes);
var msg = new proto.hello.HelloInfo;
return proto.hello.HelloInfo.deserializeBinaryFromReader(msg, reader);
};
/**
* Deserializes binary data (in protobuf wire format) from the
* given reader into the given message object.
* @param {!proto.hello.HelloInfo} msg The message object to deserialize into.
* @param {!jspb.BinaryReader} reader The BinaryReader to use.
* @return {!proto.hello.HelloInfo}
*/
proto.hello.HelloInfo.deserializeBinaryFromReader = function(msg, reader) {
while (reader.nextField()) {
if (reader.isEndGroup()) {
break;
}
var field = reader.getFieldNumber();
switch (field) {
case 1:
var value = /** @type {string} */ (reader.readString());
msg.setHelloData(value);
break;
default:
reader.skipField();
break;
}
}
return msg;
};
/**
* Serializes the message to binary data (in protobuf wire format).
* @return {!Uint8Array}
*/
proto.hello.HelloInfo.prototype.serializeBinary = function() {
var writer = new jspb.BinaryWriter();
proto.hello.HelloInfo.serializeBinaryToWriter(this, writer);
return writer.getResultBuffer();
};
/**
* Serializes the given message to binary data (in protobuf wire
* format), writing to the given BinaryWriter.
* @param {!proto.hello.HelloInfo} message
* @param {!jspb.BinaryWriter} writer
* @suppress {unusedLocalVariables} f is only used for nested messages
*/
proto.hello.HelloInfo.serializeBinaryToWriter = function(message, writer) {
var f = undefined;
f = message.getHelloData();
if (f.length > 0) {
writer.writeString(
1,
f
);
}
};
/**
* optional string hello_data = 1;
* @return {string}
*/
proto.hello.HelloInfo.prototype.getHelloData = function() {
return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 1, ""));
};
/**
* @param {string} value
* @return {!proto.hello.HelloInfo} returns this
*/
proto.hello.HelloInfo.prototype.setHelloData = function(value) {
return jspb.Message.setProto3StringField(this, 1, value);
};
goog.object.extend(exports, proto.hello);
编写client.js(只先执行一个hello方法):
var {
HelloServiceClient
} =require('./hello_grpc_web_pb');
var {
HelloRequest } =require('./hello_pb');
let client = new HelloServiceClient('http://localhost:5005');
let helloRequest = new HelloRequest();
helloRequest.setName('tom');
client.hello(helloRequest, {
}, (err, response) => {
console.log(err, response);
});
打包client.js放到dist/main.js并在index.html头部引入:
npx webpack client.js
运行index.html:
go写的服务端:
package main
import (
"context"
"fmt"
"golang-grpc-demo/hello"
"net"
"google.golang.org/grpc"
)
// HelloServerImpl 定义hello接口实现
type HelloServerImpl struct {
hello.UnimplementedHelloServiceServer
}
// Hello 定义hello的rpc方法
func (h *HelloServerImpl) Hello(ctx context.Context, request *hello.HelloRequest) (*hello.HelloInfo, error) {
name := request.GetName()
fmt.Println(name)
return &hello.HelloInfo{
HelloData: "hello " + name}, nil
}
func main() {
lis, err := net.Listen("tcp", ":8090")
if err != nil {
fmt.Println(err)
}
server := grpc.NewServer()
hello.RegisterHelloServiceServer(server, &HelloServerImpl{
})
if err := server.Serve(lis); err != nil {
fmt.Println(err)
}
}
使用这个:
也可以监听:
再写一个clientold.js(去执行sayRepeatHello方法):
var {
GreeterClient
} =require('./helloworld_grpc_web_pb');
var {
HelloRequest,RepeatHelloRequest } =require('./helloworld_pb');
let client = new GreeterClient('http://localhost:5005');
let helloRequest = new HelloRequest();
helloRequest.setName('kitty');
// helloRequest.setCity('合肥');
client.sayHello(helloRequest, {
}, (err, response) => {
console.log(err, 22,response,response.array);
});
// client.sayRepeatHello(repeatHelloRequest, {});
// server streaming call
var streamRequest = new RepeatHelloRequest();
streamRequest.setName('World');
streamRequest.setCount(7);
var stream = client.sayRepeatHello(streamRequest, {
});
stream.on('data', (response) => {
console.log(response.getMessage());
});
stream.on('error', (err) => {
console.log(`Unexpected stream error: code = ${
err.code}` +
`, message = "${err.message}"`);
});
服务端go代码:
package main
import (
"context"
"fmt"
"golang-grpc-demo/hello"
"net"
"strconv"
"google.golang.org/grpc"
)
// HelloServerImpl 定义hello接口实现
type HelloServerImpl struct {
hello.UnimplementedGreeterServer
}
// SayHello 定义hello的rpc方法
func (h *HelloServerImpl) SayHello(ctx context.Context, request *hello.HelloRequest) (*hello.HelloReply, error) {
name := request.GetName()
fmt.Println("SayHello方法接收到请求参数:", name)
return &hello.HelloReply{
Message: "SayHello: " + name}, nil
}
// SayRepeatHello 定义hello的rpc方法
func (h *HelloServerImpl) SayRepeatHello(request *hello.RepeatHelloRequest, stream hello.Greeter_SayRepeatHelloServer) error {
name := request.GetName()
count := request.GetCount()
fmt.Println("SayRepeatHello方法接收到请求参数:", name, count)
for i := 0; i < int(count); i++ {
stream.Send(&hello.HelloReply{
Message: "Count:" + strconv.Itoa(i) + " SayHello: " + name + "\n"})
}
return nil
}
func main() {
lis, err := net.Listen("tcp", ":8090")
if err != nil {
fmt.Println(err)
}
server := grpc.NewServer()
hello.RegisterGreeterServer(server, new(HelloServerImpl))
if err := server.Serve(lis); err != nil {
fmt.Println(err)
}
}
要求的类型:
测试一下,故意写一个字符串类型的次数:
结果可见:控制台报错了,请求并没有发到服务端:
文章浏览阅读198次。好消息:计算机操作员(工种代码:46-207)被确定为2011年深圳市职业技能鉴定计算机类鉴定工种学习对象:Office2003综合应用:1、向有一定电脑基础,特别是对OFFICE办公软件有一定了解,欲从事计算机日常办公的人员进行培训.2、此科目是深圳市招调工种.图形图像处理CorelDraw X3:1、从事或有意从事工艺美术、广告艺术、图文排版、图文印刷、计算机多媒体技术工作人员以及其他需要掌握..._计算机操作员职业代码
文章浏览阅读7.5k次,点赞6次,收藏47次。基于百度文心一言语言大模型的智能文本对话AI机器人API,支持聊天对话、行业咨询、语言学习、代码编写等功能.您的AppKey和uid是重要信息,请务必妥善保存,避免泄漏!您的AppKey和uid是重要信息,请务必妥善保存,避免泄漏!您的AppKey和uid是重要信息,请务必妥善保存,避免泄漏!AppKey申请通过后,登录。请求方式: POST。_文言一心api
文章浏览阅读488次。前言在每个公司的系统中,总有一些拥有复杂业务逻辑的系统,这些系统承载着核心业务逻辑,几乎每个需求都和这些核心业务有关,这些核心业务业务逻辑冗长,涉及内部逻辑运算,缓存操作,持久化操作,外部..._什么业务场景要用到编排工具
文章浏览阅读297次。题目描述若一个数(首位不为零)从左向右读与从右向左读都一样,我们就将其称之为回文数。例如:给定一个十进制数5656,将5656加6565(即把5656从右向左读),得到121121是一个回文数。又如:对于十进制数8787:STEP1:8787+7878=165165STEP2:165165+561561=726726STEP3:726726+627627=13531..._1、若一个5位数字从左向右读与从右向左读都一样,我们就将其称之为回文串。小申编
文章浏览阅读389次。[font=courier new]86. xdrx_getinters功能:1.求两个AcDbCurve(曲线)实体的交点.2.求一个AcDbCurve(曲线)实体和一个选择集中所有AcDbCurve(曲线)的交点。3.求一个选择集中所有AcDbCurve(曲线)实体的交点.4.求一个选择集SS1中的所有AcDbCurve实体和另个选择集SS2所有AcDbCurve实体的交点。调用格式: 1. ..._lisp inters
文章浏览阅读44次。Problem DescriptionBenny has a spacious farm land to irrigate. The farm land is a rectangle, and is divided into a lot of samll squares. Water pipes are placed in these squares. Different square has...
文章浏览阅读145次。官网文档: http://axis.apache.org/axis2/c/core/docs/axis2c_manual.html从文档中可以总结出:1. Axis2/C是一个用C语言实现的Web Service引擎。Axis2/C基于Axis2架构,支持SOAP1.1和SOAP1.2协议,并且支持RESTful风格的Web Service。基于Axis2/C的Web Service可以..._axis2/c服务端调用axis2_get_instance
文章浏览阅读3k次。目前主要的两种架构方法(准确的说是方法论),具体的方法也是有的,也有可实际操作层面的东西,那要看很多的各个细分专业层面的东西。比如画流程图,业务流程图、数据流程图、系统交互流程图等等。togafzachmanzachman业务建模分析框架,相比于togaf,直观上直接提供了可操作的东西,可能大家更容易接受一些。这里推荐一个架构设计的专业工具,是免费的,即ArchMateArchi – Open Source ArchiMate Modelling (archim..._企业架构方法论
文章浏览阅读123次。堆栈与队列具体的方法区分_判断是栈还是队列还是优先队列
文章浏览阅读352次,点赞8次,收藏8次。小爱老师可以购买两份双拼花束后,将他重新组合成一束百合花+一束郁金香。已知布置会场需要用到x束百合花与y束郁金香,请问小爱老师购买花朵最少花费需多少元?输出共一行,一个正整数,表示小爱老师购买花朵最少花费需多少元。直接购买8束百合+6束郁金香,共计8*8+6*10=124元。内存限制: 256 Mb时间限制: 1000 ms。先购买12束双拼花朵,花费12*8=96元,第一行:两个正整数表示需要的花束数量x,y。第二行:三个正整数表示花束费用a,b,c。再购买2束百合花,花费2*8=16元,
文章浏览阅读518次。使用Python方法比用各种命令方便,可以设置超时时间,到底通不通,端口是否开放一眼能看出来。命令和返回完整权限,可以ping通,端口开放,结果如下:无root权限(省略了ping),端口开放,结果如下:完整权限,可以ping通,远端端口关闭,结果如下:完整权限,可以ping通,本地端口关闭,结果如下:完整权限,不能ping通(端口自然也无法访问),结果如下:pnp.py代码#!/usr/bin/..._python ping ip无管理员权限
文章浏览阅读738次。零极点与系统稳定性的关系 4.状态方程含义 5.使用 zplane 函数 [实验原理] 该实验用 MATLAB 中库函数,如 tf2zp(b,a),ss2zp(A,B,C,D),zplane(z,p),......MATLAB 中相关命令 aa abs 绝对值、模、字符的 ascii 码值 a...零极点与系统稳定性的关系 4.状态方程含义 5.使用 zplane 函数 [实验原理] 该实验用 M..._matlabcla。m文件