Spring 云网关+Consul 配置
Spring Cloud Gateway+Consul configurations
我们在使用 consul 作为服务发现的多个微服务之前使用 Spring Cloud Gateway。有多种使用不同语言开发的微服务。
申请build.gradle
buildscript {
ext {
springBootVersion = '2.1.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.demo'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
}
ext {
set('springCloudVersion', 'Greenwich.RELEASE')
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-config'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.boot:spring-boot-starter-security'
// https://mvnrepository.com/artifact/io.netty/netty-tcnative-boringssl-static
compile group: 'io.netty', name: 'netty-tcnative-boringssl-static', version: '2.0.20.Final'
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
compileOnly 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
下面是API网关配置的例子
application.yaml
server:
port: 10000
http:
port: 9000
# enable HTTP2
http2:
enabled: true
# enable compression
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
ssl:
enabled: true
key-store: /var/.conf/self-signed.p12
key-store-type: PKCS12
key-store-password: "something"
key-alias: athenasowl
trust-store: /var/.conf/self-signe.p12
trust-store-password: "something"
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
predicates:
- Path="'/api/' + serviceId + '/**'"
filters:
- RewritePath="'/api/' + serviceId + '/(?<remaining>.*)'", "serviceId + '/${remaining}'"
management:
security:
enabled: false
server:
port: 10001
ssl:
enabled: false
endpoint:
gateway:
enabled: true
endpoints:
web:
exposure:
include: "*"
health:
sensitive: false
logging:
level:
root: DEBUG
org:
springframework:
web: INFO
pattern:
console: "%-5level %d{dd-MM-yyyy HH:mm:ss,SSS} [%F:%L] VTC : %msg%n"
file: "%-5level %d{dd-MM-yyyy HH:mm:ss,SSS} [%F:%L] VTC : %msg%n"
file: /tmp/log_files/apigateway.log
security:
basic:
enabled: false
我们面临一些配置问题,如下所列:
- 将前缀为/api/的URL重写为在consul上注册的相应serviceId:我们试图配置谓词以获取前缀为 api 的路径以重写路径并删除 api,但还是不行。所以有另一个服务 /hello-service/ 注册到领事服务器,但我们想用 [=65 做 API 调用=]/api/hello-service/
- 将不匹配的请求重定向到默认路径:我们希望将所有不匹配的请求重定向到UI。
- 在 spring 云网关上将 HTTP 重定向到 HTTPS:我们希望强制所有请求到达 spring 网关为 https
- Forwarding HTTPS request to HTTP serviceId registered with consul: services registered with consul are on HTTP exception of API网关,我们希望能够将 HTTPS 请求发送到 HTTP 后端,即仅在 API 网关处终止 HTTPS。
如果能帮助解决上述问题就好了
编辑 1:
在@spencergibb 的帮助下,我们已经使用 https 设置了 spring 云网关。但是我们还面临一些其他问题
- 如果 API 网关和服务都启用了 HTTPS,我们会收到以下错误
javax.net.ssl.SSLException: handshake timed out at
io.netty.handler.ssl.SslHandler.handshake(...)(Unknown Source)
~[netty-handler-4.1.31.Final.jar:4.1.31.
如果仅在 API 网关上启用 HTTPS,我们会收到以下错误
There was an unexpected error (type=Not Found, status=404).
org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND
and received
路径 https://localhost:8443/api/hello-service/hello/message
Unable to Connect
路径 http://localhost:8080/hello-service/hello/message
找到 link
说明:
- 导航到 consul 目录并使用命令启动 consul 服务器
./consul agent -dev
- 运行api-网关spring引导gradle项目
- 运行 rest-demo spring boot gradle project
编辑 2
谢谢@spencergibb,我们能够在网关上成功应用 ssl 并在 HTTP 上调用已注册的服务。自 Spring Webflux with Netty does not support listening on two ports, we created an additional tcp server bind to http port based on .
对于 /api/
规则
,RewritePath
我们仍然面临一些问题
predicates:
- name: Path
args:
pattern: "'/api/'+serviceId.toLowerCase()+'/**'"
filters:
- name: RewritePath
args:
regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
replacement: "'/${remaining}'"
下面是请求的完整跟踪
DEBUG 13-02-2019 03:32:01 [FilteringWebHandler.java:86] VTC : Sorted
gatewayFilterFactories:
[OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@257505fd},
order=-2147482648},
OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.GatewayMetricsFilter@400caab4},
order=-2147473648},
OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@36e2c50b},
order=-1},
OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardPathFilter@66f0c66d}, order=0},
OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda0/1720581802@5821f2e6,
order=0},
OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@27119239},
order=10000},
OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@568a9d8f},
order=10100},
OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@6ba77da3},
order=2147483646},
OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter@73c24516},
order=2147483647},
OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter@461a9938},
order=2147483647}] TRACE 13-02-2019 03:32:01
[RouteToRequestUrlFilter.java:59] VTC : RouteToRequestUrlFilter start
TRACE 13-02-2019 03:32:02 [NettyWriteResponseFilter.java:68] VTC :
NettyWriteResponseFilter start TRACE 13-02-2019 03:32:02
[GatewayMetricsFilter.java:101] VTC : Stopping timer
'gateway.requests' with tags
[tag(outcome=CLIENT_ERROR),tag(routeId=rewrite_response_upper),tag(routeUri=http://httpbin.org:80),tag(status=NOT_FOUN
需要很多东西
- 禁用 http2
- 禁用 httpclient 的 ssl 配置
- 更新
locator
谓词和过滤器以使用详细配置。
这是 application.yml
的结果部分
server:
port: 8443
http:
port: 8080
servlet:
# enable HTTP2
# http2:
# enabled: true
# enable compression
# ... removed for brevity
spring:
application:
name: api-gateway
cloud:
consul:
enabled: true
gateway:
# httpclient:
# ssl:
# handshake-timeout-millis: 10000
# close-notify-flush-timeout-millis: 3000
# close-notify-read-timeout-millis: 0
# routes:
# - id: ui_path_route
# predicates:
# - Path="'/**'"
# filters:
# - RewritePath="'/**'", "/ui"
discovery:
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
locator:
enabled: true
predicates:
- name: Path
args:
pattern: "'/api/' + serviceId + '/**'"
filters:
- name: RewritePath
args:
regexp: "'/api/' + serviceId + '/(?<remaining>.*)'"
replacement: "'/${remaining}'"
#... removed for brevity
我们在使用 consul 作为服务发现的多个微服务之前使用 Spring Cloud Gateway。有多种使用不同语言开发的微服务。
申请build.gradle
buildscript {
ext {
springBootVersion = '2.1.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}
apply plugin: 'java'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'
group = 'com.demo'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
maven { url 'https://repo.spring.io/milestone' }
}
ext {
set('springCloudVersion', 'Greenwich.RELEASE')
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-config'
implementation 'org.springframework.cloud:spring-cloud-starter-consul-discovery'
implementation 'org.springframework.cloud:spring-cloud-starter-gateway'
implementation 'org.springframework.boot:spring-boot-starter-security'
// https://mvnrepository.com/artifact/io.netty/netty-tcnative-boringssl-static
compile group: 'io.netty', name: 'netty-tcnative-boringssl-static', version: '2.0.20.Final'
runtimeOnly 'org.springframework.boot:spring-boot-devtools'
compileOnly 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
下面是API网关配置的例子
application.yaml
server:
port: 10000
http:
port: 9000
# enable HTTP2
http2:
enabled: true
# enable compression
compression:
enabled: true
mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/javascript,application/json
ssl:
enabled: true
key-store: /var/.conf/self-signed.p12
key-store-type: PKCS12
key-store-password: "something"
key-alias: athenasowl
trust-store: /var/.conf/self-signe.p12
trust-store-password: "something"
spring:
application:
name: api-gateway
cloud:
gateway:
discovery:
locator:
enabled: true
predicates:
- Path="'/api/' + serviceId + '/**'"
filters:
- RewritePath="'/api/' + serviceId + '/(?<remaining>.*)'", "serviceId + '/${remaining}'"
management:
security:
enabled: false
server:
port: 10001
ssl:
enabled: false
endpoint:
gateway:
enabled: true
endpoints:
web:
exposure:
include: "*"
health:
sensitive: false
logging:
level:
root: DEBUG
org:
springframework:
web: INFO
pattern:
console: "%-5level %d{dd-MM-yyyy HH:mm:ss,SSS} [%F:%L] VTC : %msg%n"
file: "%-5level %d{dd-MM-yyyy HH:mm:ss,SSS} [%F:%L] VTC : %msg%n"
file: /tmp/log_files/apigateway.log
security:
basic:
enabled: false
我们面临一些配置问题,如下所列:
- 将前缀为/api/的URL重写为在consul上注册的相应serviceId:我们试图配置谓词以获取前缀为 api 的路径以重写路径并删除 api,但还是不行。所以有另一个服务 /hello-service/ 注册到领事服务器,但我们想用 [=65 做 API 调用=]/api/hello-service/
- 将不匹配的请求重定向到默认路径:我们希望将所有不匹配的请求重定向到UI。
- 在 spring 云网关上将 HTTP 重定向到 HTTPS:我们希望强制所有请求到达 spring 网关为 https
- Forwarding HTTPS request to HTTP serviceId registered with consul: services registered with consul are on HTTP exception of API网关,我们希望能够将 HTTPS 请求发送到 HTTP 后端,即仅在 API 网关处终止 HTTPS。
如果能帮助解决上述问题就好了
编辑 1: 在@spencergibb 的帮助下,我们已经使用 https 设置了 spring 云网关。但是我们还面临一些其他问题
- 如果 API 网关和服务都启用了 HTTPS,我们会收到以下错误
javax.net.ssl.SSLException: handshake timed out at io.netty.handler.ssl.SslHandler.handshake(...)(Unknown Source) ~[netty-handler-4.1.31.Final.jar:4.1.31.
如果仅在 API 网关上启用 HTTPS,我们会收到以下错误
There was an unexpected error (type=Not Found, status=404). org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND and received
路径
https://localhost:8443/api/hello-service/hello/message
Unable to Connect
路径
http://localhost:8080/hello-service/hello/message
说明:
- 导航到 consul 目录并使用命令启动 consul 服务器
./consul agent -dev
- 运行api-网关spring引导gradle项目
- 运行 rest-demo spring boot gradle project
编辑 2
谢谢@spencergibb,我们能够在网关上成功应用 ssl 并在 HTTP 上调用已注册的服务。自 Spring Webflux with Netty does not support listening on two ports, we created an additional tcp server bind to http port based on
对于 /api/
规则
RewritePath
我们仍然面临一些问题
predicates:
- name: Path
args:
pattern: "'/api/'+serviceId.toLowerCase()+'/**'"
filters:
- name: RewritePath
args:
regexp: "'/api/' + serviceId.toLowerCase() + '/(?<remaining>.*)'"
replacement: "'/${remaining}'"
下面是请求的完整跟踪
DEBUG 13-02-2019 03:32:01 [FilteringWebHandler.java:86] VTC : Sorted gatewayFilterFactories: [OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.AdaptCachedBodyGlobalFilter@257505fd}, order=-2147482648}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.GatewayMetricsFilter@400caab4}, order=-2147473648}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyWriteResponseFilter@36e2c50b}, order=-1}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardPathFilter@66f0c66d}, order=0}, OrderedGatewayFilter{delegate=org.springframework.cloud.gateway.filter.factory.RewritePathGatewayFilterFactory$$Lambda0/1720581802@5821f2e6, order=0}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.RouteToRequestUrlFilter@27119239}, order=10000}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@568a9d8f}, order=10100}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.WebsocketRoutingFilter@6ba77da3}, order=2147483646}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter@73c24516}, order=2147483647}, OrderedGatewayFilter{delegate=GatewayFilterAdapter{delegate=org.springframework.cloud.gateway.filter.ForwardRoutingFilter@461a9938}, order=2147483647}] TRACE 13-02-2019 03:32:01 [RouteToRequestUrlFilter.java:59] VTC : RouteToRequestUrlFilter start TRACE 13-02-2019 03:32:02 [NettyWriteResponseFilter.java:68] VTC : NettyWriteResponseFilter start TRACE 13-02-2019 03:32:02 [GatewayMetricsFilter.java:101] VTC : Stopping timer 'gateway.requests' with tags [tag(outcome=CLIENT_ERROR),tag(routeId=rewrite_response_upper),tag(routeUri=http://httpbin.org:80),tag(status=NOT_FOUN
需要很多东西
- 禁用 http2
- 禁用 httpclient 的 ssl 配置
- 更新
locator
谓词和过滤器以使用详细配置。
这是 application.yml
的结果部分server:
port: 8443
http:
port: 8080
servlet:
# enable HTTP2
# http2:
# enabled: true
# enable compression
# ... removed for brevity
spring:
application:
name: api-gateway
cloud:
consul:
enabled: true
gateway:
# httpclient:
# ssl:
# handshake-timeout-millis: 10000
# close-notify-flush-timeout-millis: 3000
# close-notify-read-timeout-millis: 0
# routes:
# - id: ui_path_route
# predicates:
# - Path="'/**'"
# filters:
# - RewritePath="'/**'", "/ui"
discovery:
instanceId: ${spring.application.name}:${vcap.application.instance_id:${spring.application.instance_id:${random.value}}}
locator:
enabled: true
predicates:
- name: Path
args:
pattern: "'/api/' + serviceId + '/**'"
filters:
- name: RewritePath
args:
regexp: "'/api/' + serviceId + '/(?<remaining>.*)'"
replacement: "'/${remaining}'"
#... removed for brevity