1. Java
maven配置
点击查看代码
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.3.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>grpc-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>grpc-demo</name>
<description>grpc-demo</description>
<url/>
<licenses>
<license/>
</licenses>
<developers>
<developer/>
</developers>
<scm>
<connection/>
<developerConnection/>
<tag/>
<url/>
</scm>
<properties>
<java.version>17</java.version>
<protobuf.version>3.23.4</protobuf.version>
<protobuf-plugin.version>0.6.1</protobuf-plugin.version>
<grpc.version>1.58.0</grpc.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-netty-shaded</artifactId>
<version>1.29.0</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-stub</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-protobuf</artifactId>
<version>${grpc.version}</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>annotations-api</artifactId>
<version>6.0.53</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>net.devh</groupId>
<artifactId>grpc-server-spring-boot-starter</artifactId>
<version>3.1.0.RELEASE</version>
</dependency>
</dependencies>
<build>
<!-- os-maven-plugin:此插件可以检测当前系统信息-->
<!-- ${os.detected.classifier}:这个变量获取操作系统的版本,例如osx-x86_64-->
<extensions>
<extension>
<groupId>kr.motd.maven</groupId>
<artifactId>os-maven-plugin</artifactId>
<version>1.7.0</version>
</extension>
</extensions>
<plugins>
<plugin>
<groupId>org.xolstice.maven.plugins</groupId>
<artifactId>protobuf-maven-plugin</artifactId>
<version>${protobuf-plugin.version}</version>
<configuration>
<!-- 设置 protoc 的版本 -->
<protocArtifact>com.google.protobuf:protoc:${protobuf.version}:exe:${os.detected.classifier}</protocArtifact>
<!-- 设置插件的版本 -->
<pluginId>grpc-java</pluginId>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:${grpc.version}:exe:${os.detected.classifier}</pluginArtifact>
<!-- proto文件目录 -->
<protoSourceRoot>${project.basedir}/src/main/resources</protoSourceRoot>
<!-- 设置输出目录 -->
<outputDirectory>${project.basedir}/src/main/java</outputDirectory>
<clearOutputDirectory>false</clearOutputDirectory>
</configuration>
<executions>
<execution>
<goals>
<!--编译消息对象-->
<goal>compile</goal>
<!--依赖消息对象,生成接口服务-->
<goal>compile-custom</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
application.yml
grpc:
server:
port: 18081
proto文件
我的放在了resource目录下,是在maven配置中设置的
syntax = "proto3";
option java_multiple_files = true;
option java_package = "com.example.grpcdemo.grpc.user.auto";
option java_outer_classname = "UserProto";
service UserService {
rpc saveUser (SaveUserRequest) returns (SaveUserReply);
rpc queryUser (QueryUserRequest) returns (QueryUserReply);
}
message SaveUserRequest {
string name = 1;
string age = 2;
string sex = 3;
}
message SaveUserReply {
string status = 1;
}
message QueryUserRequest{
string name = 1;
}
message QueryUserReply{
string name = 1;
string age = 2;
string sex = 3;
}
打包之后auto文件夹下会自动生成编译后的文件
编辑你的服务类UserService
package com.example.grpcdemo.grpc.user;
import com.example.grpcdemo.grpc.user.auto.QueryUserReply;
import com.example.grpcdemo.grpc.user.auto.QueryUserRequest;
import com.example.grpcdemo.grpc.user.auto.SaveUserReply;
import com.example.grpcdemo.grpc.user.auto.SaveUserRequest;
import com.example.grpcdemo.grpc.user.auto.UserServiceGrpc;
import io.grpc.stub.StreamObserver;
import net.devh.boot.grpc.server.service.GrpcService;
@GrpcService
public class UserService extends UserServiceGrpc.UserServiceImplBase {
@Override
public void saveUser(SaveUserRequest request, StreamObserver<SaveUserReply> responseObserver) {
System.out.println(request.toBuilder().build());
SaveUserReply success = SaveUserReply.newBuilder()
.setStatus("success")
.build();
responseObserver.onNext(success);
responseObserver.onCompleted();
}
@Override
public void queryUser(QueryUserRequest request, StreamObserver<QueryUserReply> responseObserver) {
System.out.println(request.getName());
QueryUserReply reply = QueryUserReply.newBuilder()
.setAge("12")
.setName("小王")
.build();
responseObserver.onNext(reply);
responseObserver.onCompleted();
}
}
使用apiPost调用接口
附带一些常用的格式
@Override
public void query1(Query1Request request, StreamObserver<Query1Response> responseObserver) {
Query1Response response = Query1Response.newBuilder()
.addUserArr(UserObj.newBuilder().setName("小王").setAge(20).build())
.addUserArr(UserObj.newBuilder().setName("小李").setAge(21).build())
.addUserArr(UserObj.newBuilder().setName("小赵").setAge(22))
.addStringList("string1")
.addStringList("string2")
.putAMap("key1", "value1")
.putAMap("key2", "value2")
.build();
responseObserver.onNext(response);
responseObserver.onCompleted();
}
接口返回:
2. 代理
浏览器目前不支持发送http2.0的请求,所以前端使用grpc-web封装请求,经过代理请求grpc服务端。nginx代理和envoy代理都可以。
2.1 Nginx
server {
# TODO 1/2 配置监听的浏览器端口号
listen 19090;
http2 on;
server_name localhost;
location / {
# 重点!!需要将Content-Type更改为 application/grpc
# grpc-web过来的是application/grpc-web+proto || application/grpc-web+text (取决于生成js代码时grpc-web_out 的mode选项,本文用grpcweb 则为application/grpc-web+proto)
grpc_set_header Content-Type application/grpc;
# grpc_set_header TE trailers;
# TODO 2/2 配置要转到的grpc服务和端口号
grpc_pass grpc://192.168.3.100:19094;
# grpc_ssl_verify off; # 关闭对grpc服务器的ssl证书验证
# 因浏览器有跨域限制,这里直接在nginx支持跨域
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,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';
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain charset=UTF-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,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';
add_header 'Access-Control-Expose-Headers' 'Content-Transfer-Encoding, grpc-message,grpc-status';
add_header 'Content-Type' 'text/plain charset=UTF-8';
}
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
2.2 Envoy
envoy构建困难,好像目前只支持在docker部署
envoy中文网:https://icloudnative.io/envoy-handbook/docs/gettingstarted/setup/
envoy安装
# 获取镜像
docker pull envoyproxy/envoy
# 启动 Envoy 容器时,可以用本地的 envoy.yaml 覆盖镜像中的 envoy.yaml
docker run -it -d \
--name envoy \
-p 19090:19090 \
-v /home/yk/envoyConfig/envoy.yaml:/etc/envoy/envoy.yaml\
envoyproxy/envoy
# 启动envoy
envoy -c envoy.yaml
envoy.yml
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: 19090 }
filter_chains:
- filters:
- name: envoy.filters.network.http_connection_manager
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
codec_type: auto
stat_prefix: ingress_http
route_config:
name: local_route
virtual_hosts:
- name: local_service
domains: ["*"]
routes:
- match: { prefix: "/" }
route:
cluster: echo_service
timeout: 0s
max_stream_duration:
grpc_timeout_header_max: 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.filters.http.grpc_web
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.grpc_web.v3.GrpcWeb
- name: envoy.filters.http.cors
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.cors.v3.Cors
- name: envoy.filters.http.router
typed_config:
"@type": type.googleapis.com/envoy.extensions.filters.http.router.v3.Router
clusters:
- name: echo_service
connect_timeout: 0.25s
type: logical_dns
# HTTP/2 support
typed_extension_protocol_options:
envoy.extensions.upstreams.http.v3.HttpProtocolOptions:
"@type": type.googleapis.com/envoy.extensions.upstreams.http.v3.HttpProtocolOptions
explicit_http_config:
http2_protocol_options: {}
lb_policy: round_robin
load_assignment:
cluster_name: cluster_0
endpoints:
- lb_endpoints:
- endpoint:
address:
socket_address:
address: 192.168.3.100
port_value: 19094
标签:springboot,grpc,demo,envoy,header,type,com,name
From: https://www.cnblogs.com/krcc/p/18385123