├── .gitignore ├── README.adoc ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── grpc-client ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── grpcclient │ │ │ └── GrpcClientApplication.java │ ├── proto │ │ └── hello.proto │ └── resources │ │ ├── application.properties │ │ ├── cert.key │ │ └── certificate.pem │ └── test │ └── java │ └── com │ └── example │ └── grpcclient │ └── GrpcClientApplicationTests.java ├── grpc-json-gateway.png ├── grpc-json-gateway ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── grpcserver │ │ │ └── hello │ │ │ ├── JSONToGRPCFilterFactory.java │ │ │ └── SpringCloudGatewayGrpcApplication.java │ ├── proto │ │ └── hello.proto │ └── resources │ │ ├── application.yaml │ │ └── keystore.p12 │ └── test │ └── java │ └── com │ └── example │ └── grpcserver │ └── hello │ └── SpringCloudGatewayGrpcApplicationTests.java ├── grpc-server ├── .gitignore ├── README.md ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── grpcserver │ │ │ ├── GrpcServerApplication.java │ │ │ └── HelloServiceImpl.java │ ├── proto │ │ └── hello.proto │ └── resources │ │ ├── application.yaml │ │ ├── cert.key │ │ ├── certificate.pem │ │ └── keystore.p12 │ └── test │ └── java │ └── com │ └── example │ └── grpcserver │ └── GrpcServerApplicationTests.java ├── grpc-simple-gateway.png ├── grpc-simple-gateway ├── .gitignore ├── build.gradle ├── gradle │ └── wrapper │ │ ├── gradle-wrapper.jar │ │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── settings.gradle └── src │ ├── main │ ├── java │ │ └── com │ │ │ └── example │ │ │ └── grpcserver │ │ │ └── hello │ │ │ └── SpringCloudGatewayGrpcApplication.java │ └── resources │ │ ├── application.yaml │ │ └── keystore.p12 │ └── test │ └── java │ └── com │ └── example │ └── grpcserver │ └── hello │ └── SpringCloudGatewayGrpcApplicationTests.java └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /README.adoc: -------------------------------------------------------------------------------- 1 | = Spring Cloud Gateway and gRPC 2 | 3 | Starting from `3.1.0` as part of the Spring Cloud 2021.0.0 (aka Jubilee) release train, Spring Cloud Gateway included support for gRPC and HTTP/2. 4 | 5 | We will introduce the basic concepts behind gRPC and how to configure it with two examples: 6 | 7 | * One that showcases how Spring Cloud Gateway can transparently re-route gRPC traffic without needing to know the proto definition and without having to modify our existing gRPC servers. 8 | 9 | * Another that showcases how we can create a custom filter in Spring Cloud Gateway to transform a JSON payload to a gRPC message. 10 | 11 | 12 | == Introduction to gRPC and HTTP/2 13 | 14 | HTTP/2 makes our applications faster, simpler, and more robust. Reducing latency by enabling request and response 15 | multiplexing, adding efficient compression of HTTP header fields, and adding support for request prioritization and 16 | server push. 17 | 18 | The reduction in the number of connections is particularly important when improving the performance of HTTPS: that way 19 | we have less expensive TLS handshakes, more efficient session reuse, reducing client and server resources. 20 | 21 | HTTP/2 provides two mechanisms for negotiating the application level protocol: 22 | 23 | * `H2C` HTTP/2.0 support with clear-text 24 | * `H2` HTTP/2.0 support with TLS 25 | 26 | Even though `reactor-netty` has support for `H2C` clear-text protocol, Spring Cloud Gateway requires `H2` with TLS to 27 | assure transport security. 28 | 29 | HTTP/2 adds a binary framing layer, which is how the HTTP messages are encapsulated and transferred between the client 30 | and server, enabling more efficient ways to transfer data. 31 | 32 | Thanks to https://github.com/reactor/reactor-netty[reactor-netty] and its HTTP/2 support, we were able to extend 33 | Spring Cloud Gateway to support gRPC. 34 | 35 | https://grpc.io/[gRPC] is a high-performance Remote Procedure Call framework that can run in any environment. It 36 | provides bi-directional streaming, and it's based on HTTP/2. 37 | 38 | gRPC services can be defined using Protocol Buffers, a powerful binary serialization toolset and language, and 39 | provides tools for generating clients and servers across different languages. 40 | 41 | == Getting started 42 | 43 | In order to enable gRPC in Spring Cloud Gateway, we need to enable HTTP/2 and SSL in our project https://docs.oracle.com/cd/E19830-01/819-4712/ablqw/index.html[by adding a keystore], this can be done 44 | through configuration by adding the following: 45 | 46 | [source,yaml] 47 | ---- 48 | server: 49 | http2: 50 | enabled: true 51 | ssl: 52 | key-store-type: PKCS12 53 | key-store: classpath:keystore.p12 54 | key-store-password: password 55 | key-password: password 56 | enabled: true 57 | 58 | ---- 59 | 60 | Now that we have it enabled, we can create a route that redirects traffic to a gRPC server and take advantage of the 61 | existing filters and predicates, for example, this route will redirect traffic that comes from any path starting 62 | with `grpc` to a local server in the port `6565` and add header `X-Request-header` with the value `header-value`: 63 | 64 | [source,yaml] 65 | ---- 66 | spring: 67 | cloud: 68 | gateway: 69 | routes: 70 | - id: grpc 71 | uri: https://localhost:6565 72 | predicates: 73 | - Path=/grpc/** 74 | filters: 75 | - AddResponseHeader=X-Request-header, header-value 76 | ---- 77 | 78 | == Running gRPC to gRPC 79 | 80 | An end to end example can be found in this repository with the following parts: 81 | 82 | image::grpc-simple-gateway.png[grpc-simple-gateway] 83 | 84 | 85 | * A `grpc-server` that exposes a `HelloService`, and gRPC endpoint to receive a `HelloRequest` and return 86 | a `HelloResponse`: 87 | [source,protobuf] 88 | ---- 89 | syntax = "proto3"; 90 | 91 | message HelloRequest { 92 | string firstName = 1; 93 | string lastName = 2; 94 | } 95 | 96 | message HelloResponse { 97 | string greeting = 1; 98 | } 99 | 100 | service HelloService { 101 | rpc hello(HelloRequest) returns (HelloResponse); 102 | } 103 | ---- 104 | 105 | The server will concatenate a salutation with `firstName` and a `lastName` and respond with a `greeting`. 106 | 107 | For example, this input: 108 | 109 | [source,text] 110 | ---- 111 | firstName: Saul 112 | lastName: Hudson 113 | ---- 114 | 115 | Will output: 116 | 117 | [source,text] 118 | ---- 119 | greeting: Hello, Saul Hudson 120 | ---- 121 | 122 | * A `grpc-client`, in charge of sending the `HelloRequest` to the `HelloService`. 123 | 124 | * `grpc-simple-gateway` that routes the requests and adds a header with the configuration mentioned above. Note that this gateway application does not have any dependency to gRPC nor to the proto definition used by client and server. 125 | 126 | At the moment there is just one route that will forward everything to the `grpc-server`: 127 | 128 | [source,yaml] 129 | ---- 130 | routes: 131 | - id: grpc 132 | uri: https://localhost:6565 133 | predicates: 134 | - Path=/** 135 | filters: 136 | - AddResponseHeader=X-Request-header, header-value 137 | ---- 138 | 139 | To start the server that is going to be listening to requests: 140 | 141 | [source,shell] 142 | ---- 143 | ./gradlew :grpc-server:bootRun 144 | ---- 145 | 146 | Then, we start the gateway that is going to re-route the gRPC requests: 147 | 148 | [source,shell] 149 | ---- 150 | ./gradlew :grpc-simple-gateway:bootRun 151 | ---- 152 | 153 | Finally, we can use the client that points to the gateway application: 154 | 155 | [source,shell] 156 | ---- 157 | ./gradlew :grpc-client:bootRun 158 | ---- 159 | 160 | The gateway routes and filters can be modified in https://github.com/Albertoimpl/spring-cloud-gateway-grpc/blob/5bf80a24a8adf0d5d7c1614524f9d55707536c19/grpc-simple-gateway/src/main/resources/application.yaml#L14[grpc-simple-gateway/src/main/resources/application.yaml] 161 | 162 | == Running JSON to gRPC with a custom filter 163 | 164 | Thanks to Spring Cloud Gateway flexibility, it is possible to create a custom filter to transform from a JSON payload to 165 | a gRPC message. 166 | 167 | Even though it will have a performance impact since we have to serialize and deserialize the requests in the gateway and creating a channel from it, 168 | it is a common pattern if you want to expose a JSON API while maintaining internal compatibility. 169 | 170 | For that, we can extend our `grpc-json-gateway` to include the `proto` definition with the message we want to send. 171 | 172 | image::grpc-json-gateway.png[grpc-json-gateway] 173 | 174 | 175 | Spring Cloud Gateway contains a mechanism to create custom filters allowing us to intercept requests and add custom logic to them. 176 | 177 | For this particular scenario, we are going to deserialize the JSON request and create a gRPC channel that will send a message to the `grpc-server`. 178 | 179 | [source,java] 180 | ---- 181 | static class GRPCResponseDecorator extends ServerHttpResponseDecorator { 182 | 183 | @Override 184 | public Mono writeWith(Publisher body) { 185 | exchange.getResponse().getHeaders().set("Content-Type", "application/json"); 186 | 187 | URI requestURI = exchange.getRequest().getURI(); 188 | ManagedChannel channel = createSecuredChannel(requestURI.getHost(), 6565); 189 | 190 | return getDelegate().writeWith(deserializeJSONRequest() 191 | .map(jsonRequest -> { 192 | String firstName = jsonRequest.getFirstName(); 193 | String lastName = jsonRequest.getLastName(); 194 | return HelloServiceGrpc.newBlockingStub(channel) 195 | .hello(HelloRequest.newBuilder() 196 | .setFirstName(firstName) 197 | .setLastName(lastName) 198 | .build()); 199 | }) 200 | .map(this::serialiseJSONResponse) 201 | .map(wrapGRPCResponse()) 202 | .cast(DataBuffer.class) 203 | .last()); 204 | } 205 | } 206 | ---- 207 | 208 | The full implementation can be found 209 | in: https://github.com/Albertoimpl/spring-cloud-gateway-grpc/blob/5bf80a24a8adf0d5d7c1614524f9d55707536c19/grpc-json-gateway/src/main/java/com/example/grpcserver/hello/JSONToGRPCFilterFactory.java#L38[grpc-json-gateway/src/main/java/com/example/grpcserver/hello/JSONToGRPCFilterFactory.java] 210 | 211 | Using the same `grpc-server`, we can start the gateway with the custom filter with: 212 | 213 | [source,shell] 214 | ---- 215 | ./gradlew :grpc-json-gateway:bootRun 216 | ---- 217 | 218 | And send JSON requests to the `grpc-json-gateway` using, for example, `curl`: 219 | 220 | [source,bash] 221 | ---- 222 | curl -XPOST 'https://localhost:8091/json/hello' -d '{"firstName":"Duff","lastName":"McKagan"}' -k -H"Content-Type: application/json" -v 223 | ---- 224 | 225 | We see how the gateway application forwards the requests and returns the JSON payload with the new `Content-Type` header: 226 | 227 | [source,bash] 228 | ---- 229 | < HTTP/2 200 230 | < content-type: application/json 231 | < content-length: 34 232 | < 233 | * Connection #0 to host localhost left intact 234 | {"greeting":"Hello, Duff McKagan"} 235 | ---- 236 | 237 | == Next Steps 238 | 239 | In this post, we've looked at a few examples of how gRPC can be integrated within Spring Cloud Gateway. I’d love to know 240 | what other usages you've found to be helpful in your experiences. 241 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.1-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | # 4 | # Copyright 2015 the original author or authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | ## 21 | ## Gradle start up script for UN*X 22 | ## 23 | ############################################################################## 24 | 25 | # Attempt to set APP_HOME 26 | # Resolve links: $0 may be a link 27 | PRG="$0" 28 | # Need this for relative symlinks. 29 | while [ -h "$PRG" ] ; do 30 | ls=`ls -ld "$PRG"` 31 | link=`expr "$ls" : '.*-> \(.*\)$'` 32 | if expr "$link" : '/.*' > /dev/null; then 33 | PRG="$link" 34 | else 35 | PRG=`dirname "$PRG"`"/$link" 36 | fi 37 | done 38 | SAVED="`pwd`" 39 | cd "`dirname \"$PRG\"`/" >/dev/null 40 | APP_HOME="`pwd -P`" 41 | cd "$SAVED" >/dev/null 42 | 43 | APP_NAME="Gradle" 44 | APP_BASE_NAME=`basename "$0"` 45 | 46 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 47 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 48 | 49 | # Use the maximum available, or set MAX_FD != -1 to use that value. 50 | MAX_FD="maximum" 51 | 52 | warn () { 53 | echo "$*" 54 | } 55 | 56 | die () { 57 | echo 58 | echo "$*" 59 | echo 60 | exit 1 61 | } 62 | 63 | # OS specific support (must be 'true' or 'false'). 64 | cygwin=false 65 | msys=false 66 | darwin=false 67 | nonstop=false 68 | case "`uname`" in 69 | CYGWIN* ) 70 | cygwin=true 71 | ;; 72 | Darwin* ) 73 | darwin=true 74 | ;; 75 | MSYS* | MINGW* ) 76 | msys=true 77 | ;; 78 | NONSTOP* ) 79 | nonstop=true 80 | ;; 81 | esac 82 | 83 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 84 | 85 | 86 | # Determine the Java command to use to start the JVM. 87 | if [ -n "$JAVA_HOME" ] ; then 88 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 89 | # IBM's JDK on AIX uses strange locations for the executables 90 | JAVACMD="$JAVA_HOME/jre/sh/java" 91 | else 92 | JAVACMD="$JAVA_HOME/bin/java" 93 | fi 94 | if [ ! -x "$JAVACMD" ] ; then 95 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 96 | 97 | Please set the JAVA_HOME variable in your environment to match the 98 | location of your Java installation." 99 | fi 100 | else 101 | JAVACMD="java" 102 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 103 | 104 | Please set the JAVA_HOME variable in your environment to match the 105 | location of your Java installation." 106 | fi 107 | 108 | # Increase the maximum file descriptors if we can. 109 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 110 | MAX_FD_LIMIT=`ulimit -H -n` 111 | if [ $? -eq 0 ] ; then 112 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 113 | MAX_FD="$MAX_FD_LIMIT" 114 | fi 115 | ulimit -n $MAX_FD 116 | if [ $? -ne 0 ] ; then 117 | warn "Could not set maximum file descriptor limit: $MAX_FD" 118 | fi 119 | else 120 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 121 | fi 122 | fi 123 | 124 | # For Darwin, add options to specify how the application appears in the dock 125 | if $darwin; then 126 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 127 | fi 128 | 129 | # For Cygwin or MSYS, switch paths to Windows format before running java 130 | if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then 131 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 132 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 133 | 134 | JAVACMD=`cygpath --unix "$JAVACMD"` 135 | 136 | # We build the pattern for arguments to be converted via cygpath 137 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 138 | SEP="" 139 | for dir in $ROOTDIRSRAW ; do 140 | ROOTDIRS="$ROOTDIRS$SEP$dir" 141 | SEP="|" 142 | done 143 | OURCYGPATTERN="(^($ROOTDIRS))" 144 | # Add a user-defined pattern to the cygpath arguments 145 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 146 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 147 | fi 148 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 149 | i=0 150 | for arg in "$@" ; do 151 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 152 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 153 | 154 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 155 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 156 | else 157 | eval `echo args$i`="\"$arg\"" 158 | fi 159 | i=`expr $i + 1` 160 | done 161 | case $i in 162 | 0) set -- ;; 163 | 1) set -- "$args0" ;; 164 | 2) set -- "$args0" "$args1" ;; 165 | 3) set -- "$args0" "$args1" "$args2" ;; 166 | 4) set -- "$args0" "$args1" "$args2" "$args3" ;; 167 | 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 168 | 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 169 | 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 170 | 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 171 | 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 172 | esac 173 | fi 174 | 175 | # Escape application args 176 | save () { 177 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 178 | echo " " 179 | } 180 | APP_ARGS=`save "$@"` 181 | 182 | # Collect all arguments for the java command, following the shell quoting and substitution rules 183 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 184 | 185 | exec "$JAVACMD" "$@" 186 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /grpc-client/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /grpc-client/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.5.11' 3 | id 'io.spring.dependency-management' version '1.0.11.RELEASE' 4 | id 'java' 5 | id "io.github.lognet.grpc-spring-boot" version '4.6.0' 6 | } 7 | 8 | apply plugin: 'com.google.protobuf' 9 | apply plugin: 'io.spring.dependency-management' 10 | 11 | grpcSpringBoot { 12 | grpcSpringBootStarterVersion.set((String) null) 13 | } 14 | 15 | group = 'com.example' 16 | version = '0.0.1-SNAPSHOT' 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/milestone' } 21 | } 22 | 23 | dependencies { 24 | implementation 'io.github.lognet:grpc-spring-boot-starter:4.6.0' 25 | implementation 'org.springframework.boot:spring-boot-starter-webflux' 26 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 27 | testImplementation 'io.projectreactor:reactor-test' 28 | } 29 | 30 | test { 31 | useJUnitPlatform() 32 | } 33 | -------------------------------------------------------------------------------- /grpc-client/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-client/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /grpc-client/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /grpc-client/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /grpc-client/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /grpc-client/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'grpc-client' 2 | -------------------------------------------------------------------------------- /grpc-client/src/main/java/com/example/grpcclient/GrpcClientApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcclient; 2 | 3 | import com.example.grpcserver.hello.HelloRequest; 4 | import com.example.grpcserver.hello.HelloResponse; 5 | import com.example.grpcserver.hello.HelloServiceGrpc; 6 | import io.grpc.ManagedChannel; 7 | import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; 8 | import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; 9 | import org.springframework.boot.ApplicationArguments; 10 | import org.springframework.boot.ApplicationRunner; 11 | import org.springframework.boot.SpringApplication; 12 | import org.springframework.boot.autoconfigure.SpringBootApplication; 13 | 14 | import javax.net.ssl.SSLException; 15 | import javax.net.ssl.TrustManager; 16 | import javax.net.ssl.X509TrustManager; 17 | import java.security.cert.X509Certificate; 18 | 19 | import static io.grpc.netty.shaded.io.grpc.netty.NegotiationType.TLS; 20 | 21 | @SpringBootApplication 22 | public class GrpcClientApplication implements ApplicationRunner { 23 | 24 | public static void main(String[] args) { 25 | SpringApplication.run(GrpcClientApplication.class, args); 26 | } 27 | 28 | @Override 29 | public void run(ApplicationArguments args) throws SSLException { 30 | 31 | int gatewayPort = 8090; 32 | ManagedChannel channel = createSecuredChannel(gatewayPort); 33 | 34 | final HelloResponse response = HelloServiceGrpc.newBlockingStub(channel) 35 | .hello(HelloRequest.newBuilder().setFirstName("Saul") 36 | .setLastName("Hudson").build()); 37 | 38 | System.out.println(response.toString()); 39 | } 40 | 41 | private ManagedChannel createSecuredChannel(int port) throws SSLException { 42 | TrustManager[] trustAllCerts = new TrustManager[]{ 43 | new X509TrustManager() { 44 | public X509Certificate[] getAcceptedIssuers() { 45 | return new X509Certificate[0]; 46 | } 47 | 48 | public void checkClientTrusted(X509Certificate[] certs, 49 | String authType) { 50 | } 51 | 52 | public void checkServerTrusted(X509Certificate[] certs, 53 | String authType) { 54 | } 55 | }}; 56 | 57 | return NettyChannelBuilder.forAddress("localhost", port) 58 | .useTransportSecurity().sslContext( 59 | GrpcSslContexts.forClient().trustManager(trustAllCerts[0]) 60 | .build()).negotiationType(TLS).build(); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /grpc-client/src/main/proto/hello.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option java_multiple_files = true; 3 | package com.example.grpcserver.hello; 4 | 5 | message HelloRequest { 6 | string firstName = 1; 7 | string lastName = 2; 8 | } 9 | 10 | message HelloResponse { 11 | string greeting = 1; 12 | } 13 | 14 | service HelloService { 15 | rpc hello(HelloRequest) returns (HelloResponse); 16 | } 17 | -------------------------------------------------------------------------------- /grpc-client/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | server.port=8085 2 | -------------------------------------------------------------------------------- /grpc-client/src/main/resources/cert.key: -------------------------------------------------------------------------------- 1 | Bag Attributes 2 | friendlyName: mykey 3 | localKeyID: 54 69 6D 65 20 31 36 33 32 38 32 34 38 37 31 33 33 35 4 | Key Attributes: 5 | -----BEGIN PRIVATE KEY----- 6 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCMHrxh2N9GHaFH 7 | Qkgf+au/xXNCh3rXY2+9RtrurxXXjb0sDKQlfGdSc5zif9c7mPtGddOUAjzO34tQ 8 | AovrasQ0fi+8o1B4VBDE4hoAh3GCSGWQmH1ktwUF1cYDkV4Q7+0XbglGgi55GhWP 9 | vojzE1MtAlcSJKZSBIQJqnIpCIFmmuWYwZHoCoGoZT0CypXw+Ec/5Ktj/iy2BbBz 10 | TXSn1r+l0LuCzMO2RACbX3aWjE85rUIqW07eg4fO7yGtAiFZwj3ZUN6P+VnmsRAN 11 | aZ3zi2rNO9VXR4odpwubx4UHEz0A32vrsM0L8x63IY7rzFFGWgmCc7k9Bup2xgW2 12 | ueBAU+8lAgMBAAECggEAGu2xQJDAYCZDn4FCgTqnYkSdIRUOa6SFjfe3DZYCeZmY 13 | 2IVZaobdCICFjxYIlECTUfhFADXp38wgZvEGWOj86iWyIOu2BFoLmvrlCmL9Uo99 14 | TWuw9ZEi2vs5gegHDvQ9OXqBN9a+/bEgoa55fVWib4z6lNcMS8joYz8pj28+ByzE 15 | LW0/3T3p6beM2fUcCJWn3d2M3wUgSuXmcdjVXJSkhEwKTVcc4vTTcOeF6xb2VZ/g 16 | Pozv/39G1qZ+QtM58yBiqnJ1Z2gtAk71l/1ztQa3uY22gzw8Kj5dmqcHgdiN5DWI 17 | bNE+k5Q93FzUmZNYPzmY6YVkdEzaNMtmi96sdtEu5QKBgQD36YdGXUyoRXeNDRuc 18 | yMXr6j/9/ewii+byHhFoUvjLuXWIQ06V+nOtYqohg/zgGIiC5LQ8EB0uFZDMhbDf 19 | kSwtoXbpUDLYD2OPgIyLaPqHiYQ9BampbUz5vHlfYLr0vB+Xp5r22Eb6nDQRRtb5 20 | EXHoYgAokgpYdeTIcdKRcB/2DwKBgQCQsPePeu7PagM9vYEo4zfbFxfY3Qkr4lOQ 21 | BCZ/tgsS0b0jAAxpfUH0/3O5oXizmB/5K7vgKqGnTuBWJJ/hdCWq27FkKxJ+8ejU 22 | 8V9TFd5VQ89VeB5OekZwPks8vftwzW4L82ZRW5hvyQB0jPR+lwqjrNqds+xxH7i+ 23 | c+RFx15biwKBgQCgkGGK0zao7YUGl+zAWNDHgQo9KM5deZr0SUEg/kwhNlbHEEC/ 24 | plxxeauS1XdcdMdFb3bER/N+O31y2Uu7IL0qOJ9ZcRXdFep3sNxWFoHcctZw51AB 25 | accnIEjD21R62bTkditJoL4n5i9a2TS2T/QkfAR6QkvtCz5IDGBCzgoFRQKBgC51 26 | VBfy3gklPgMt/PHW+1FSuep9FnvLwQ8F9iKdnjKdu8AoPNQGTw5Ok6bwDOSFnQaR 27 | n1Kb/anN7sRaICfw9kNFJVFHbznpjNwK4JO5+tif3EvSNND3+/QAXIIVck3G+GXH 28 | 8nt/EJQcExRZSgv3jYf+cXeflPTBvb0RUyOAn3B/AoGAM9aUi2dg3XjlDkZahQlY 29 | P5QNIr9BY25Ordga3GLwfR6rE+jiWTeTmreXBSJ7nvcaEQUNyFMX9n3v/QI84etk 30 | lMJkZ4o2TgzRnCsFJoBV36Ihsa6B5uXVWAvMRLKvwKpptKXfO0TnhUg7oKtN4t3a 31 | /FzAOS2Eu1PFP27z74gAMKY= 32 | -----END PRIVATE KEY----- 33 | -------------------------------------------------------------------------------- /grpc-client/src/main/resources/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDdzCCAl+gAwIBAgIEIon96DANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV 3 | bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD 4 | VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du 5 | MB4XDTIxMDkyNzE2NDQwNVoXDTMxMDkyNTE2NDQwNVowbDEQMA4GA1UEBhMHVW5r 6 | bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE 7 | ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC 8 | ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIwevGHY30YdoUdCSB/5q7/F 9 | c0KHetdjb71G2u6vFdeNvSwMpCV8Z1JznOJ/1zuY+0Z105QCPM7fi1ACi+tqxDR+ 10 | L7yjUHhUEMTiGgCHcYJIZZCYfWS3BQXVxgORXhDv7RduCUaCLnkaFY++iPMTUy0C 11 | VxIkplIEhAmqcikIgWaa5ZjBkegKgahlPQLKlfD4Rz/kq2P+LLYFsHNNdKfWv6XQ 12 | u4LMw7ZEAJtfdpaMTzmtQipbTt6Dh87vIa0CIVnCPdlQ3o/5WeaxEA1pnfOLas07 13 | 1VdHih2nC5vHhQcTPQDfa+uwzQvzHrchjuvMUUZaCYJzuT0G6nbGBba54EBT7yUC 14 | AwEAAaMhMB8wHQYDVR0OBBYEFKOHmfytP5ab2C4iFHlSklu6tCcuMA0GCSqGSIb3 15 | DQEBCwUAA4IBAQAdgWwdOtRbI796Z22weTBc0/tM8kLc6G0raNb08WyZMPZVki04 16 | jPh73pPQCgYeI/pq5JqH46KgvehmygTzpWDAFIllW0kgABVw3Nu6duV+blt1JG8T 17 | lWP7t5A+qDXgPDm3I5diii7O1YlLB3I37XiBdEV/+2WmF1VGQ7uBWAv+uotQeuW2 18 | JvHOr4ICOiW45TzRYtAbzWukSYKg/A7lwBs7HE9KVomUxNrkD+7+ugRuy/31pyen 19 | pHsEJQpx5juFRE222B6GXmX0w9xLIOapytl4EoPUx3K8Ecc+yI2q00UUC43x0v28 20 | c05YqwRZ5vp+jUnRxkxaz85YdArfR7QFYWtO 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /grpc-client/src/test/java/com/example/grpcclient/GrpcClientApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcclient; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class GrpcClientApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /grpc-json-gateway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-json-gateway.png -------------------------------------------------------------------------------- /grpc-json-gateway/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /grpc-json-gateway/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.6.2' 3 | id 'io.spring.dependency-management' version '1.0.11.RELEASE' 4 | id 'java' 5 | id "io.github.lognet.grpc-spring-boot" version '4.6.0' 6 | } 7 | 8 | apply plugin: 'com.google.protobuf' 9 | apply plugin: 'io.spring.dependency-management' 10 | 11 | grpcSpringBoot { 12 | grpcSpringBootStarterVersion.set((String)null) 13 | } 14 | 15 | group = 'com.example' 16 | version = '0.0.1-SNAPSHOT' 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/milestone' } 21 | } 22 | 23 | ext { 24 | set('springCloudVersion', "2021.0.1") 25 | } 26 | 27 | dependencies { 28 | implementation 'io.github.lognet:grpc-spring-boot-starter:4.6.0' 29 | implementation 'org.springframework.boot:spring-boot-starter-webflux' 30 | 31 | implementation 'org.springframework.cloud:spring-cloud-starter-gateway' 32 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 33 | } 34 | 35 | dependencyManagement { 36 | imports { 37 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 38 | } 39 | } 40 | 41 | test { 42 | useJUnitPlatform() 43 | } 44 | -------------------------------------------------------------------------------- /grpc-json-gateway/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-json-gateway/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /grpc-json-gateway/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /grpc-json-gateway/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /grpc-json-gateway/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /grpc-json-gateway/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'grpc-json-gateway' 2 | -------------------------------------------------------------------------------- /grpc-json-gateway/src/main/java/com/example/grpcserver/hello/JSONToGRPCFilterFactory.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcserver.hello; 2 | 3 | import com.fasterxml.jackson.core.JsonProcessingException; 4 | import com.fasterxml.jackson.databind.ObjectMapper; 5 | import io.grpc.ManagedChannel; 6 | import io.grpc.netty.shaded.io.grpc.netty.GrpcSslContexts; 7 | import io.grpc.netty.shaded.io.grpc.netty.NettyChannelBuilder; 8 | import io.netty.buffer.PooledByteBufAllocator; 9 | import org.reactivestreams.Publisher; 10 | import org.springframework.cloud.gateway.filter.GatewayFilter; 11 | import org.springframework.cloud.gateway.filter.GatewayFilterChain; 12 | import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter; 13 | import org.springframework.cloud.gateway.filter.OrderedGatewayFilter; 14 | import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; 15 | import org.springframework.core.ResolvableType; 16 | import org.springframework.core.io.buffer.DataBuffer; 17 | import org.springframework.core.io.buffer.NettyDataBufferFactory; 18 | import org.springframework.http.codec.json.Jackson2JsonDecoder; 19 | import org.springframework.http.server.reactive.ServerHttpResponseDecorator; 20 | import org.springframework.stereotype.Component; 21 | import org.springframework.web.server.ServerWebExchange; 22 | import reactor.core.publisher.Flux; 23 | import reactor.core.publisher.Mono; 24 | 25 | import javax.net.ssl.SSLException; 26 | import javax.net.ssl.TrustManager; 27 | import javax.net.ssl.X509TrustManager; 28 | import java.io.Serializable; 29 | import java.net.URI; 30 | import java.security.cert.X509Certificate; 31 | import java.util.Objects; 32 | import java.util.function.Function; 33 | 34 | import static io.grpc.netty.shaded.io.grpc.netty.NegotiationType.TLS; 35 | import static org.springframework.cloud.gateway.support.GatewayToStringStyler.filterToStringCreator; 36 | 37 | @Component 38 | public class JSONToGRPCFilterFactory extends AbstractGatewayFilterFactory { 39 | 40 | @Override 41 | public GatewayFilter apply(Object config) { 42 | GatewayFilter filter = new GatewayFilter() { 43 | @Override 44 | public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { 45 | GRPCResponseDecorator modifiedResponse = new GRPCResponseDecorator(exchange); 46 | 47 | return modifiedResponse 48 | .writeWith(exchange.getRequest().getBody()) 49 | .then(chain.filter(exchange.mutate() 50 | .response(modifiedResponse).build())); 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | return filterToStringCreator( 56 | JSONToGRPCFilterFactory.this) 57 | .toString(); 58 | } 59 | }; 60 | 61 | int order = NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1; 62 | return new OrderedGatewayFilter(filter, order); 63 | } 64 | 65 | @Override 66 | public String name() { 67 | return "JSONToGRPCFilter"; 68 | } 69 | 70 | static class GRPCResponseDecorator extends ServerHttpResponseDecorator { 71 | 72 | private final ServerWebExchange exchange; 73 | 74 | public GRPCResponseDecorator(ServerWebExchange exchange) { 75 | super(exchange.getResponse()); 76 | this.exchange = exchange; 77 | } 78 | 79 | @Override 80 | public Mono writeWith(Publisher body) { 81 | exchange.getResponse().getHeaders().set("Content-Type", "application/json"); 82 | 83 | URI requestURI = exchange.getRequest().getURI(); 84 | ManagedChannel channel = createSecuredChannel(requestURI.getHost(), 6565); 85 | 86 | return getDelegate().writeWith(deserializeJSONRequest() 87 | .map(jsonRequest -> { 88 | String firstName = jsonRequest.getFirstName(); 89 | String lastName = jsonRequest.getLastName(); 90 | return HelloServiceGrpc.newBlockingStub(channel) 91 | .hello(HelloRequest.newBuilder() 92 | .setFirstName(firstName) 93 | .setLastName(lastName) 94 | .build()); 95 | }) 96 | .map(this::serialiseJSONResponse) 97 | .map(wrapGRPCResponse()) 98 | .cast(DataBuffer.class) 99 | .last()); 100 | } 101 | 102 | private Flux deserializeJSONRequest() { 103 | return exchange.getRequest() 104 | .getBody() 105 | .mapNotNull(dataBufferBody -> { 106 | ResolvableType targetType = ResolvableType.forType(PersonHello.class); 107 | return new Jackson2JsonDecoder() 108 | .decode(dataBufferBody, targetType, null, null); 109 | }) 110 | .cast(PersonHello.class); 111 | } 112 | 113 | private GreetingHello serialiseJSONResponse(HelloResponse gRPCResponse) { 114 | return new GreetingHello(gRPCResponse.getGreeting()); 115 | } 116 | 117 | private Function wrapGRPCResponse() { 118 | return jsonResponse -> { 119 | try { 120 | return new NettyDataBufferFactory(new PooledByteBufAllocator()) 121 | .wrap(Objects.requireNonNull(new ObjectMapper() 122 | .writeValueAsBytes(jsonResponse))); 123 | } catch (JsonProcessingException e) { 124 | return new NettyDataBufferFactory(new PooledByteBufAllocator()) 125 | .allocateBuffer(); 126 | } 127 | }; 128 | } 129 | 130 | private ManagedChannel createSecuredChannel(String host, int port) { 131 | TrustManager[] trustAllCerts = new TrustManager[]{ 132 | new X509TrustManager() { 133 | public X509Certificate[] getAcceptedIssuers() { 134 | return new X509Certificate[0]; 135 | } 136 | 137 | public void checkClientTrusted(X509Certificate[] certs, 138 | String authType) { 139 | } 140 | 141 | public void checkServerTrusted(X509Certificate[] certs, 142 | String authType) { 143 | } 144 | }}; 145 | 146 | try { 147 | return NettyChannelBuilder.forAddress(host, port) 148 | .useTransportSecurity().sslContext( 149 | GrpcSslContexts.forClient().trustManager(trustAllCerts[0]) 150 | .build()).negotiationType(TLS).build(); 151 | } catch (SSLException e) { 152 | e.printStackTrace(); 153 | } 154 | throw new RuntimeException(); 155 | } 156 | 157 | } 158 | 159 | static class PersonHello { 160 | 161 | private String firstName; 162 | private String lastName; 163 | 164 | public PersonHello() { 165 | } 166 | 167 | public PersonHello(String firstName, String lastName) { 168 | this.firstName = firstName; 169 | this.lastName = lastName; 170 | } 171 | 172 | public String getFirstName() { 173 | return firstName; 174 | } 175 | 176 | public void setFirstName(String firstName) { 177 | this.firstName = firstName; 178 | } 179 | 180 | public String getLastName() { 181 | return lastName; 182 | } 183 | 184 | public void setLastName(String lastName) { 185 | this.lastName = lastName; 186 | } 187 | } 188 | 189 | static class GreetingHello implements Serializable { 190 | 191 | private static final long serialVersionUID = 1L; 192 | 193 | private String greeting; 194 | 195 | public GreetingHello() { 196 | } 197 | 198 | public GreetingHello(String greeting) { 199 | this.greeting = greeting; 200 | } 201 | 202 | public String getGreeting() { 203 | return greeting; 204 | } 205 | 206 | public void setGreeting(String greeting) { 207 | this.greeting = greeting; 208 | } 209 | } 210 | 211 | } 212 | -------------------------------------------------------------------------------- /grpc-json-gateway/src/main/java/com/example/grpcserver/hello/SpringCloudGatewayGrpcApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcserver.hello; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringCloudGatewayGrpcApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringCloudGatewayGrpcApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /grpc-json-gateway/src/main/proto/hello.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option java_multiple_files = true; 3 | package com.example.grpcserver.hello; 4 | 5 | message HelloRequest { 6 | string firstName = 1; 7 | string lastName = 2; 8 | } 9 | 10 | message HelloResponse { 11 | string greeting = 1; 12 | } 13 | 14 | service HelloService { 15 | rpc hello(HelloRequest) returns (HelloResponse); 16 | } 17 | -------------------------------------------------------------------------------- /grpc-json-gateway/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8091 3 | http2: 4 | enabled: true 5 | ssl: 6 | key-store-type: PKCS12 7 | key-store: classpath:keystore.p12 8 | key-store-password: password 9 | key-password: password 10 | enabled: true 11 | spring: 12 | cloud: 13 | gateway: 14 | httpclient: 15 | ssl: 16 | use-insecure-trust-manager: true 17 | 18 | routes: 19 | - id: json-grpc 20 | uri: https://localhost:6565 21 | predicates: 22 | - Path=/json/** 23 | filters: 24 | - JSONToGRPCFilter 25 | logging: 26 | level: 27 | reactor.netty: DEBUG 28 | org.springframework.cloud.gateway.filter: TRACE 29 | -------------------------------------------------------------------------------- /grpc-json-gateway/src/main/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-json-gateway/src/main/resources/keystore.p12 -------------------------------------------------------------------------------- /grpc-json-gateway/src/test/java/com/example/grpcserver/hello/SpringCloudGatewayGrpcApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcserver.hello; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpringCloudGatewayGrpcApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /grpc-server/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /grpc-server/README.md: -------------------------------------------------------------------------------- 1 | ```shell 2 | keytool -genkeypair -keyalg RSA -keysize 2048 -storetype PKCS12 -keystore keystore.p12 -validity 3650 3 | keytool -genkeypair -keyalg RSA -keysize 2048 -keystore keystore.jks -validity 3650 4 | keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -deststoretype pkcs12 5 | ``` 6 | -------------------------------------------------------------------------------- /grpc-server/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.5.11' 3 | id 'io.spring.dependency-management' version '1.0.11.RELEASE' 4 | id 'java' 5 | id "io.github.lognet.grpc-spring-boot" version '4.6.0' 6 | } 7 | 8 | apply plugin: 'com.google.protobuf' 9 | apply plugin: 'io.spring.dependency-management' 10 | 11 | grpcSpringBoot { 12 | grpcSpringBootStarterVersion.set((String) null) 13 | } 14 | 15 | group = 'com.example' 16 | version = '0.0.1-SNAPSHOT' 17 | 18 | repositories { 19 | mavenCentral() 20 | maven { url 'https://repo.spring.io/milestone' } 21 | } 22 | 23 | dependencies { 24 | implementation 'io.github.lognet:grpc-spring-boot-starter:4.6.0' 25 | implementation 'org.springframework.boot:spring-boot-starter-webflux' 26 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 27 | testImplementation 'io.projectreactor:reactor-test' 28 | } 29 | 30 | test { 31 | useJUnitPlatform() 32 | } 33 | -------------------------------------------------------------------------------- /grpc-server/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-server/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /grpc-server/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /grpc-server/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /grpc-server/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /grpc-server/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'grpc-server' 2 | -------------------------------------------------------------------------------- /grpc-server/src/main/java/com/example/grpcserver/GrpcServerApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcserver; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class GrpcServerApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(GrpcServerApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /grpc-server/src/main/java/com/example/grpcserver/HelloServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcserver; 2 | 3 | import com.example.grpcserver.hello.HelloRequest; 4 | import com.example.grpcserver.hello.HelloResponse; 5 | import com.example.grpcserver.hello.HelloServiceGrpc; 6 | import io.grpc.stub.StreamObserver; 7 | import org.lognet.springboot.grpc.GRpcService; 8 | 9 | @GRpcService 10 | public class HelloServiceImpl extends HelloServiceGrpc.HelloServiceImplBase { 11 | 12 | @Override 13 | public void hello( 14 | HelloRequest request, StreamObserver responseObserver) { 15 | 16 | String greeting = new StringBuilder() 17 | .append("Hello, ") 18 | .append(request.getFirstName()) 19 | .append(" ") 20 | .append(request.getLastName()) 21 | .toString(); 22 | System.out.println(greeting); 23 | 24 | HelloResponse response = HelloResponse.newBuilder() 25 | .setGreeting(greeting) 26 | .build(); 27 | 28 | responseObserver.onNext(response); 29 | responseObserver.onCompleted(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /grpc-server/src/main/proto/hello.proto: -------------------------------------------------------------------------------- 1 | syntax = "proto3"; 2 | option java_multiple_files = true; 3 | package com.example.grpcserver.hello; 4 | 5 | message HelloRequest { 6 | string firstName = 1; 7 | string lastName = 2; 8 | } 9 | 10 | message HelloResponse { 11 | string greeting = 1; 12 | } 13 | 14 | service HelloService { 15 | rpc hello(HelloRequest) returns (HelloResponse); 16 | } 17 | -------------------------------------------------------------------------------- /grpc-server/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | grpc: 2 | enableReflection: true 3 | enabled: true 4 | security: 5 | cert-chain: classpath:certificate.pem 6 | private-key: classpath:cert.key 7 | server: 8 | port: 8082 9 | 10 | logging: 11 | level: 12 | io.netty: TRACE -------------------------------------------------------------------------------- /grpc-server/src/main/resources/cert.key: -------------------------------------------------------------------------------- 1 | Bag Attributes 2 | friendlyName: mykey 3 | localKeyID: 54 69 6D 65 20 31 36 33 32 38 32 34 38 37 31 33 33 35 4 | Key Attributes: 5 | -----BEGIN PRIVATE KEY----- 6 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCMHrxh2N9GHaFH 7 | Qkgf+au/xXNCh3rXY2+9RtrurxXXjb0sDKQlfGdSc5zif9c7mPtGddOUAjzO34tQ 8 | AovrasQ0fi+8o1B4VBDE4hoAh3GCSGWQmH1ktwUF1cYDkV4Q7+0XbglGgi55GhWP 9 | vojzE1MtAlcSJKZSBIQJqnIpCIFmmuWYwZHoCoGoZT0CypXw+Ec/5Ktj/iy2BbBz 10 | TXSn1r+l0LuCzMO2RACbX3aWjE85rUIqW07eg4fO7yGtAiFZwj3ZUN6P+VnmsRAN 11 | aZ3zi2rNO9VXR4odpwubx4UHEz0A32vrsM0L8x63IY7rzFFGWgmCc7k9Bup2xgW2 12 | ueBAU+8lAgMBAAECggEAGu2xQJDAYCZDn4FCgTqnYkSdIRUOa6SFjfe3DZYCeZmY 13 | 2IVZaobdCICFjxYIlECTUfhFADXp38wgZvEGWOj86iWyIOu2BFoLmvrlCmL9Uo99 14 | TWuw9ZEi2vs5gegHDvQ9OXqBN9a+/bEgoa55fVWib4z6lNcMS8joYz8pj28+ByzE 15 | LW0/3T3p6beM2fUcCJWn3d2M3wUgSuXmcdjVXJSkhEwKTVcc4vTTcOeF6xb2VZ/g 16 | Pozv/39G1qZ+QtM58yBiqnJ1Z2gtAk71l/1ztQa3uY22gzw8Kj5dmqcHgdiN5DWI 17 | bNE+k5Q93FzUmZNYPzmY6YVkdEzaNMtmi96sdtEu5QKBgQD36YdGXUyoRXeNDRuc 18 | yMXr6j/9/ewii+byHhFoUvjLuXWIQ06V+nOtYqohg/zgGIiC5LQ8EB0uFZDMhbDf 19 | kSwtoXbpUDLYD2OPgIyLaPqHiYQ9BampbUz5vHlfYLr0vB+Xp5r22Eb6nDQRRtb5 20 | EXHoYgAokgpYdeTIcdKRcB/2DwKBgQCQsPePeu7PagM9vYEo4zfbFxfY3Qkr4lOQ 21 | BCZ/tgsS0b0jAAxpfUH0/3O5oXizmB/5K7vgKqGnTuBWJJ/hdCWq27FkKxJ+8ejU 22 | 8V9TFd5VQ89VeB5OekZwPks8vftwzW4L82ZRW5hvyQB0jPR+lwqjrNqds+xxH7i+ 23 | c+RFx15biwKBgQCgkGGK0zao7YUGl+zAWNDHgQo9KM5deZr0SUEg/kwhNlbHEEC/ 24 | plxxeauS1XdcdMdFb3bER/N+O31y2Uu7IL0qOJ9ZcRXdFep3sNxWFoHcctZw51AB 25 | accnIEjD21R62bTkditJoL4n5i9a2TS2T/QkfAR6QkvtCz5IDGBCzgoFRQKBgC51 26 | VBfy3gklPgMt/PHW+1FSuep9FnvLwQ8F9iKdnjKdu8AoPNQGTw5Ok6bwDOSFnQaR 27 | n1Kb/anN7sRaICfw9kNFJVFHbznpjNwK4JO5+tif3EvSNND3+/QAXIIVck3G+GXH 28 | 8nt/EJQcExRZSgv3jYf+cXeflPTBvb0RUyOAn3B/AoGAM9aUi2dg3XjlDkZahQlY 29 | P5QNIr9BY25Ordga3GLwfR6rE+jiWTeTmreXBSJ7nvcaEQUNyFMX9n3v/QI84etk 30 | lMJkZ4o2TgzRnCsFJoBV36Ihsa6B5uXVWAvMRLKvwKpptKXfO0TnhUg7oKtN4t3a 31 | /FzAOS2Eu1PFP27z74gAMKY= 32 | -----END PRIVATE KEY----- 33 | -------------------------------------------------------------------------------- /grpc-server/src/main/resources/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIDdzCCAl+gAwIBAgIEIon96DANBgkqhkiG9w0BAQsFADBsMRAwDgYDVQQGEwdV 3 | bmtub3duMRAwDgYDVQQIEwdVbmtub3duMRAwDgYDVQQHEwdVbmtub3duMRAwDgYD 4 | VQQKEwdVbmtub3duMRAwDgYDVQQLEwdVbmtub3duMRAwDgYDVQQDEwdVbmtub3du 5 | MB4XDTIxMDkyNzE2NDQwNVoXDTMxMDkyNTE2NDQwNVowbDEQMA4GA1UEBhMHVW5r 6 | bm93bjEQMA4GA1UECBMHVW5rbm93bjEQMA4GA1UEBxMHVW5rbm93bjEQMA4GA1UE 7 | ChMHVW5rbm93bjEQMA4GA1UECxMHVW5rbm93bjEQMA4GA1UEAxMHVW5rbm93bjCC 8 | ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIwevGHY30YdoUdCSB/5q7/F 9 | c0KHetdjb71G2u6vFdeNvSwMpCV8Z1JznOJ/1zuY+0Z105QCPM7fi1ACi+tqxDR+ 10 | L7yjUHhUEMTiGgCHcYJIZZCYfWS3BQXVxgORXhDv7RduCUaCLnkaFY++iPMTUy0C 11 | VxIkplIEhAmqcikIgWaa5ZjBkegKgahlPQLKlfD4Rz/kq2P+LLYFsHNNdKfWv6XQ 12 | u4LMw7ZEAJtfdpaMTzmtQipbTt6Dh87vIa0CIVnCPdlQ3o/5WeaxEA1pnfOLas07 13 | 1VdHih2nC5vHhQcTPQDfa+uwzQvzHrchjuvMUUZaCYJzuT0G6nbGBba54EBT7yUC 14 | AwEAAaMhMB8wHQYDVR0OBBYEFKOHmfytP5ab2C4iFHlSklu6tCcuMA0GCSqGSIb3 15 | DQEBCwUAA4IBAQAdgWwdOtRbI796Z22weTBc0/tM8kLc6G0raNb08WyZMPZVki04 16 | jPh73pPQCgYeI/pq5JqH46KgvehmygTzpWDAFIllW0kgABVw3Nu6duV+blt1JG8T 17 | lWP7t5A+qDXgPDm3I5diii7O1YlLB3I37XiBdEV/+2WmF1VGQ7uBWAv+uotQeuW2 18 | JvHOr4ICOiW45TzRYtAbzWukSYKg/A7lwBs7HE9KVomUxNrkD+7+ugRuy/31pyen 19 | pHsEJQpx5juFRE222B6GXmX0w9xLIOapytl4EoPUx3K8Ecc+yI2q00UUC43x0v28 20 | c05YqwRZ5vp+jUnRxkxaz85YdArfR7QFYWtO 21 | -----END CERTIFICATE----- 22 | -------------------------------------------------------------------------------- /grpc-server/src/main/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-server/src/main/resources/keystore.p12 -------------------------------------------------------------------------------- /grpc-server/src/test/java/com/example/grpcserver/GrpcServerApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcserver; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class GrpcServerApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /grpc-simple-gateway.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-simple-gateway.png -------------------------------------------------------------------------------- /grpc-simple-gateway/.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | .gradle 3 | build/ 4 | !gradle/wrapper/gradle-wrapper.jar 5 | !**/src/main/**/build/ 6 | !**/src/test/**/build/ 7 | 8 | ### STS ### 9 | .apt_generated 10 | .classpath 11 | .factorypath 12 | .project 13 | .settings 14 | .springBeans 15 | .sts4-cache 16 | bin/ 17 | !**/src/main/**/bin/ 18 | !**/src/test/**/bin/ 19 | 20 | ### IntelliJ IDEA ### 21 | .idea 22 | *.iws 23 | *.iml 24 | *.ipr 25 | out/ 26 | !**/src/main/**/out/ 27 | !**/src/test/**/out/ 28 | 29 | ### NetBeans ### 30 | /nbproject/private/ 31 | /nbbuild/ 32 | /dist/ 33 | /nbdist/ 34 | /.nb-gradle/ 35 | 36 | ### VS Code ### 37 | .vscode/ 38 | -------------------------------------------------------------------------------- /grpc-simple-gateway/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'org.springframework.boot' version '2.6.2' 3 | id 'io.spring.dependency-management' version '1.0.11.RELEASE' 4 | id 'java' 5 | } 6 | 7 | group = 'org.springframework.cloud.gateway.samples' 8 | version = '0.0.1-SNAPSHOT' 9 | sourceCompatibility = '11' 10 | 11 | repositories { 12 | mavenCentral() 13 | maven { url 'https://repo.spring.io/milestone' } 14 | } 15 | 16 | ext { 17 | set('springCloudVersion', "2021.0.1") 18 | } 19 | 20 | dependencies { 21 | implementation 'org.springframework.cloud:spring-cloud-starter-gateway' 22 | testImplementation 'org.springframework.boot:spring-boot-starter-test' 23 | } 24 | 25 | dependencyManagement { 26 | imports { 27 | mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}" 28 | } 29 | } 30 | 31 | test { 32 | useJUnitPlatform() 33 | } 34 | -------------------------------------------------------------------------------- /grpc-simple-gateway/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-simple-gateway/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /grpc-simple-gateway/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /grpc-simple-gateway/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /grpc-simple-gateway/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /grpc-simple-gateway/settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'grpc-simple-gateway' 2 | -------------------------------------------------------------------------------- /grpc-simple-gateway/src/main/java/com/example/grpcserver/hello/SpringCloudGatewayGrpcApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcserver.hello; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class SpringCloudGatewayGrpcApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(SpringCloudGatewayGrpcApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /grpc-simple-gateway/src/main/resources/application.yaml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8090 3 | http2: 4 | enabled: true 5 | ssl: 6 | key-store-type: PKCS12 7 | key-store: classpath:keystore.p12 8 | key-store-password: password 9 | key-password: password 10 | enabled: true 11 | spring: 12 | cloud: 13 | gateway: 14 | httpclient: 15 | ssl: 16 | use-insecure-trust-manager: true 17 | 18 | routes: 19 | - id: grpc 20 | uri: https://localhost:6565 21 | predicates: 22 | - Path=/** 23 | filters: 24 | - AddResponseHeader=X-Request-header, header-value -------------------------------------------------------------------------------- /grpc-simple-gateway/src/main/resources/keystore.p12: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Albertoimpl/spring-cloud-gateway-grpc/9a52a9a98773aa52fbc589529c3a7944f899902f/grpc-simple-gateway/src/main/resources/keystore.p12 -------------------------------------------------------------------------------- /grpc-simple-gateway/src/test/java/com/example/grpcserver/hello/SpringCloudGatewayGrpcApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.grpcserver.hello; 2 | 3 | import org.junit.jupiter.api.Test; 4 | import org.springframework.boot.test.context.SpringBootTest; 5 | 6 | @SpringBootTest 7 | class SpringCloudGatewayGrpcApplicationTests { 8 | 9 | @Test 10 | void contextLoads() { 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | pluginManagement { 2 | repositories { 3 | maven { url 'https://repo.spring.io/milestone' } 4 | gradlePluginPortal() 5 | } 6 | } 7 | 8 | rootProject.name = 'spring-cloud-gateway-grpc' 9 | 10 | include "grpc-json-gateway" 11 | include "grpc-simple-gateway" 12 | include "grpc-server" 13 | include "grpc-client" 14 | 15 | --------------------------------------------------------------------------------