参考文献:
https://blog.csdn.net/qq_45634989/article/details/128151766
依赖文件:
protoc-v3-20.1.exe
grpc_cpp_plugin.exe // 生成cpp中间文件
protoc-gen-grpc-web.exe // 生成js中间文件
grpcwebproxy-v0.13.0-win64 1.4.0.exe // 负责代理的端口映射
新建测试工程文件夹grpcweb-cpp并下载grpc-web工程 ( git clone https://gitcode.net/mirrors/grpc/grpc-web.git )
新建一个package.json文件,填入下面内容:
{
"name": "grpc-web",
"version": "0.1.0",
"description": "gRPC-Web simple example",
"main": "server.js",
"devDependencies": {
"google-protobuf": "~3.14.0",
"grpc-web": "~1.4.2",
"lodash": "~4.17.0",
"webpack": "~4.43.0",
"webpack-cli": "~3.3.11"
},
"dependencies": {
"document": "^0.4.7",
"xmlhttprequest": "^1.8.0"
}
}
在当前文件夹下执行 npm install 命令,下载依赖
创建TestServer.proto接口文件,并通过protoc和protoc-gen-grpc-web生成js中间文件,proto内容如下:
syntax = "proto3";
package PDS_LifeDB;
service TestServer {
rpc SayHello(HelloRequest) returns (HelloReply);
}
message HelloRequest {
string name = 1;
}
message HelloReply {
string message = 1;
}
分别执行如下两行代码,生成中间文件 (commjs:. 和grpcwebtext:. 的点号表示在当前路径下生成)
protoc-v3-20.1 --js_out=import_style=commonjs:. TestServer.proto
protoc-v3-20.1 --grpc-web_out=import_style=commonjs,mode=grpcwebtext:. --plugin=protoc-gen-grpc=protoc-gen-grpc-web.exe TestServer.proto
创建client.js文件,注意导入的类是TestServerClient名称,此外URL地址和端口号,这里写的是代理的端口号7150不是后端服务的端口号7152,记住这些配置,后面会用到,具体内容如下:
const {HelloRequest,HelloReply} = require('./TestServer_pb.js');
const {TestServerClient} = require('./TestServer_grpc_web_pb.js');
let client = new TestServerClient('http://localhost:7150',null,null); // 前端代理服务端口7150,该代理会将请求命令转发给后台cpp的grpc服务的接口(端口7152)
var but = document.getElementById('bu')
//这里设置了一个点击事件,当点击按钮的时候,再向服务端发送请求
//按钮要联系到index.html文件上
but.onclick = function () {
var request = new HelloRequest();
request.setName('World');
client.sayHello(request, {}, (err, response) => {
if (err) {
console.log(`Unexpected error for sayHello: code = ${err.code}` +
`, message = "${err.message}"`);
} else {
console.log(response.getMessage());
}
});
}
生成main.js文件,还是在当前路径下,执行如下命令
set NODE_OPTIONS=--openssl-legacy-provider
npx webpack client.js
执行完之后,将在当前路径下生成一个文件夹dist,里面包含main.js.
创建index.html文件,具体内容如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>PDS_LifeDB-TestServer</title>
</head>
<body>
<p>实现前端通过js或者ts直接调用后台cpp的grpc服务</p>
<button id="btn" >测试</button>
<script src="./dist/main.js"></script>
</body>
</html>
创建server文件夹,通过protoc和grpc_cpp_plugin工具生成cpp版本的中间文件。这里我们用vs2019工具,给大家演示一下如何快速实现cpp版本的中间文件的生成以及后面服务的实现。
7-1 新建一个grpcTestServer.sln解决工程,并添加两个空工程,分别是ITestServer和TestServer。接着在ITestServer中添加刚刚我们创建的TestServer.proto文件,具体如下图所示:
7-2 添加TestServer.proto文件并修改文件属性
右键TestServer.proto文件,在弹出的属性中,修改《常规》下面的《项类型》,选择"自定义生成工具";单击"应用",之后会出现"自定义生成工具"选项卡,具体如下图所示
7-3 命令行中传命令给protoc和grpc_cpp_plugin工具,用于生成中间存根文件
protoc --cpp_out=../TestServer TestServer.proto
protoc --grpc_out=../TestServer --plugin=protoc-gen-grpc=grpc_cpp_plugin.exe TestServer.proto
设置好之后,不要急着编译,先将两个工具protoc和grpc_cpp_plugin拷贝到当前文件夹下,注意此时的protoc.exe的版本是3.21.6。不是刚才的v3.20.1版本,这个主要是我们编译的grpc的lib版本原因。
重新编译,之后将在TestServer文件夹中生成四个存根代理文件,具体如下图所示:
实现TestServer服务
8-1:添加依赖文件和lib库文件,具体依赖lib文件如下:
upb.lib
re2.lib
cares.lib
gpr.lib
grpc++.lib
grpc.lib
address_sorting.lib
libprotobufd.lib
ssl.lib
crypto.lib
zlibstaticd.lib
absl_bad_optional_access.lib
absl_bad_variant_access.lib
absl_base.lib
absl_city.lib
absl_civil_time.lib
absl_cord.lib
absl_cordz_functions.lib
absl_cordz_handle.lib
absl_cordz_info.lib
absl_cordz_sample_token.lib
absl_cord_internal.lib
absl_debugging_internal.lib
absl_demangle_internal.lib
absl_examine_stack.lib
absl_exponential_biased.lib
absl_failure_signal_handler.lib
absl_flags.lib
absl_flags_commandlineflag.lib
absl_flags_commandlineflag_internal.lib
absl_flags_config.lib
absl_flags_internal.lib
absl_flags_marshalling.lib
absl_flags_parse.lib
absl_flags_private_handle_accessor.lib
absl_flags_program_name.lib
absl_flags_reflection.lib
absl_flags_usage.lib
absl_flags_usage_internal.lib
absl_graphcycles_internal.lib
absl_hash.lib
absl_hashtablez_sampler.lib
absl_int128.lib
absl_leak_check.lib
absl_log_severity.lib
absl_low_level_hash.lib
absl_malloc_internal.lib
absl_periodic_sampler.lib
absl_random_distributions.lib
absl_random_internal_distribution_test_util.lib
absl_random_internal_platform.lib
absl_random_internal_pool_urbg.lib
absl_random_internal_randen.lib
absl_random_internal_randen_hwaes.lib
absl_random_internal_randen_hwaes_impl.lib
absl_random_internal_randen_slow.lib
absl_random_internal_seed_material.lib
absl_random_seed_gen_exception.lib
absl_random_seed_sequences.lib
absl_raw_hash_set.lib
absl_raw_logging_internal.lib
absl_symbolize.lib
absl_synchronization.lib
absl_throw_delegate.lib
absl_scoped_set_env.lib
absl_spinlock_wait.lib
absl_stacktrace.lib
absl_status.lib
absl_statusor.lib
absl_strerror.lib
absl_strings.lib
absl_strings_internal.lib
absl_str_format_internal.lib
absl_time.lib
absl_time_zone.lib
添加中间存根文件并实现接口服务
#include <iostream>
#include "TestServer.grpc.pb.h"
#include "TestServer.pb.h"
#include "grpc++/grpc++.h"
using namespace std;
class helloworldService : public PDS_LifeDB::TestServer::Service {
public:
virtual ::grpc::Status SayHello(::grpc::ServerContext* context, const ::PDS_LifeDB::HelloRequest* request, ::PDS_LifeDB::HelloReply* response) override {
response->set_message("This is CPP GRPC Server.");
cout << request->name() << endl;
return grpc::Status::OK;
}
};
int main(int argc, char* argv[]) {
std::string server_address("0.0.0.0:5152");
helloworldService calcSrv;
grpc::ServerBuilder builder;
builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
builder.RegisterService(&calcSrv);
std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
std::cout << "Server listening on " << server_address << std::endl;
server->Wait();
return 0;
}
编译TestServer并启动CPP版本GRPC服务
通过grpcwebproxy-v0.13.0-win64工具进行跳转,执行如下命令
grpcwebproxy-v0.13.0-win64.exe --allow_all_origins --backend_addr=localhost:7152 --run_tls_server=false --server_http_debug_port=7150 --allow_all_origins=true
开始测试,浏览器打开index.html