Spring Cloud Gateway+ Консул конфигурации
Мы используем 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
Есть несколько проблем с конфигурацией, с которыми мы сталкиваемся, они перечислены ниже:
- Перезаписать URL с префиксом /api/ на соответствующий serviceId, зарегистрированный на консул: Мы пытались настроить предикат, чтобы путь с префиксом api переписывал путь и удалял api, но все же он не работает. Таким образом, есть другой сервис / hello-service / зарегистрированный на консул-сервере, но мы хотим сделать вызов API с /api/hello-service/
- Перенаправить несопоставленный запрос в путь по умолчанию: Мы хотим перенаправить все несопоставленные запросы в пользовательский интерфейс.
- Перенаправление HTTP на HTTPS на весеннем облачном шлюзе: мы хотим, чтобы все запросы, поступающие на весенний шлюз, были https
- Пересылка HTTPS-запроса в HTTP-сервис. Идентификатор, зарегистрированный в консул: Сервисы, зарегистрированные в консул, работают по HTTP, за исключением шлюза API, мы хотим иметь возможность отправлять HTTPS-запрос в HTTP-бэкэнд, то есть завершать HTTPS только в API-шлюзе.
Любая помощь в решении вышеуказанного вопроса будет хорошей
Редактировать 1: После некоторой помощи от @spencergibb мы настроили весенний облачный шлюз с https. Но есть некоторые дополнительные проблемы, с которыми мы столкнулись
- Если HTTPS включен как на шлюзе API, так и на сервисе, мы получили ошибку ниже
javax.net.ssl.SSLException: время ожидания рукопожатия на io.netty.handler.ssl.SslHandler.handshake(...)(неизвестный источник) ~[netty-handler-4.1.31.Final.jar:4.1.31.
Если HTTPS включен только на API-шлюзе, мы получили сообщение об ошибке ниже
Произошла непредвиденная ошибка (тип = Не найдено, статус =404). org.springframework.web.server.ResponseStatusException: 404 NOT_FOUND и получено
для пути
https://localhost:8443/api/hello-service/hello/message
Невозможно подключиться
для пути
http://localhost:8080/hello-service/hello/message
Пожалуйста, найдите ссылку для примеров приложений
Инструкции:
- перейдите в каталог консул и запустите консул сервер с помощью команды
./consul agent -dev
- запустить api-gateway проект весенней загрузки gradle
- запустить rest-demo проект весенней загрузки gradle
Редактировать 2
Спасибо @spencergibb, мы смогли успешно применить ssl на шлюзе и вызвать зарегистрированные сервисы по HTTP. Поскольку Spring Webflux с Netty не поддерживает прослушивание двух портов, мы создали дополнительную привязку tcp-сервера к порту http на основе этого ответа.
Есть еще проблема, с которой мы сталкиваемся RewritePath
за /api/
правило
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: отсортированные gatewayFilterFactories: [OrderedGatewayFilter‹delegate=GatewayFilterAdapter averagedelegate=org.springframework.cloud.gateway.filter.AdaptCachedBody }505F5B5_5 2147482648}, OrderedGatewayFilter averagedelegate=GatewayFilterAdapter enjdelegate=org.springframework.cloud.gateway.filter.GatewayMetricsFilter@400caab4}, order=-2147473648}, OrderedGatewayFilter{Delegate = Gatewayclilf.NETtyWriteResponseFilter@36e2c50b}, order=-1}, OrderedGatewayFilter enjdelegate=GatewayFilterAdapter‹delegate=org.springframework.cloud.gateway.filter.ForwardPathFilter@66f0c66d}, order=0} oroud.gatefategate.filter.factory. rderedGatewayFilter enjdelegate=GatewayFilterAdapter averagedelegate=org.springframework.cloud.gateway.filter.LoadBalancerClientFilter@568a9d8f}, order=10100}, OrderedGatewayFilter enjdelegate=GatewayFilter.gatewayerter.Wizard.Farter.File.terf.WardFid.Ru.FidGateWate.Werver.File.Ru.Ru.RidGatewayFilter&dexate.GatewayFilter.Wid.Web.File.Ward.Ru.WR.Wid.Ru.Ru.Ru.Ru.Ru.Ru.Ru.Ru., order=2147483646}, OrderedGatewayFilter]delegate=GatewayFilterAdapter enjdelegate=org.springframework.cloud.gateway.filter.NettyRoutingFilter@73c24516}, order=2147483647}, OrderedGatewayFilter{Delegate = GatewayFate.fater.file.filter.ForwardRoutingFilter@461a9938}, заказ =2147483647}] TRACE 13-02-2019 03:32:01 [RouteToRequestUrlFilter.java:59] VTC: RouteToRequestUrlFilter start TRACE 13-02-2019 03:32:02 [NettyWriteResponseFilter:68] VTC: запуск NettyWriteResponseFilter TRACE 13-02-2019 03:32:02 [GatewayMetricsFilter.java:101] VTC: останов таймера 'gateway.requests' с тегами [тег (исход =CLIENT_ERROR), тег (routeId = rewrite_response_upper), tag (routeUri = http: // httpbin. орг: 80), тег (статус = NOT_FOUN
1 ответ
Нужно было несколько вещей
- отключить http2
- Отключить ssl-конфигурацию httpclient
- Обновить
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