I have a spring cloud project. This project consists of three main parts: A service discovery with Eureka, A gateway with Spring Cloud Gateway and service for REST API endpoints. I want to define API endpoints like this:
GET
/available
and route them with a path predicate in gateway:
GET
/service-one/available
To achieve this, I've added this route in gateway's yml file:
spring:
cloud:
gateway:
routes:
- id: service_one
uri: lb://service_one
predicates:
- Path=/service-one/**
filters:
- StripPrefix=1
but when I try
// 9000 is the gateway's port number
http://localhost:9000/service-one/available
I get this error:
{
"timestamp": "...",
"path": "/service-one/available",
"status": 404,
"error": "Not Found",
"message": null,
"requestId": "..."
}
More details:
Spring Boot version: 2.4.5
Spring Cloud version: 2020.0.2
Discovery:
pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
application.properties:
server.port=8761
spring.application.name=discovery
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
Application startup:
#SpringBootApplication
#EnableEurekaServer
public class DiscoveryApplication {
// ...
}
Gateway:
pom.xml:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.yml:
spring:
application:
name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
httpclient:
wiretap: true
httpserver:
wiretap: true
routes:
##
##
- id: service_one
uri: lb://service_one
predicates:
- Path=/service-one/**
filters:
- StripPrefix=1
##
##
eureka:
client:
register-with-eureka: false
Service:
pom.xml:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
application.properties:
spring.application.name=service_one
server.port=8080
eureka.client.register-with-eureka=true
eureka.client.service-url.default-zone=http://localhost:8761/eureka
Service Endpoint:
#SpringBootApplication
#EnableEurekaClient
#RestController
public class ServiceOneApplication {
// ...
#GetMapping("/available")
public String available() {
return "Hi, Service One is available";
}
}
Related
I have a microservices project with 5 apps running in separate docker containers: 2 app services, 2 databases and the Eureka Discovery service. They are running in the same network. Eureka server UI is up and displaying at localhost:8761. Eureka is not displaying any clients. Here are the pertinent files and info:
discovery-service
EurekaServerApplication
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
#EnableEurekaServer
#SpringBootApplication
public class EurekaServerApplication {
public static void main(String[] args) {
org.springframework.boot.SpringApplication.run(EurekaServerApplication.class, args);
}
}
application.yml
spring:
application:
name: eureka-server
cloud:
config:
import-check:
enabled: false
main:
web-application-type: reactive
server:
port: 8761
eureka:
client:
fetch-registry: false
register-with-eureka: false
service:
url:
defaultZone: ${EUREKA_URI:http://localhost:8761}/eureka/}
instance:
hostname: localhost
logging:
level:
root: Error
employee-service
EmployeeServiceApplication
package com.microservices;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
#EnableDiscoveryClient
#SpringBootApplication
public class EmployeeServiceApplication {
public static void main(String[] args) {
SpringApplication.run(EmployeeServiceApplication.class, args);
}
}
application.yml
server:
port: 8084
spring:
application:
name: employee-service
datasource:
username: postgres
password: secret
url: jdbc:postgresql://localhost:5432/employee
main:
web:
application-type: reactive
jpa:
hibernate:
ddl-auto: validate
defer-datasource-initialization: true
properties:
hibernate:
dialect: org.hibernate.dialect.PostgreSQLDialect
format_sql: true
show-sql: true
profiles:
active: default
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka/
logging:
level:
org:
hibernate:
SQL: WARN
springframework:
boot:
autoconfigure: ERROR
root: ERROR
Pertinent Maven Dependencies
<properties>
<release.train.version>2022.0.0</release.train.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
<spring.boot.dependencies.version>3.0.1</spring.boot.dependencies.version>
<spring.boot.maven.plugin.version>3.0.1</spring.boot.maven.plugin.version>
<spring.boot.maven.compiler.plugin.version>3.9.0</spring.boot.maven.compiler.plugin.version>
<spring-security.version>6.0.1</spring-security.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${release.train.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>${release.train.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring.boot.dependencies.version}</version>
<scope>import</scope>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring-security.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>${spring.boot.dependencies.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>${spring.boot.dependencies.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<version>${spring.boot.dependencies.version}</version>
<type>pom</type>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<version>${spring.boot.dependencies.version}</version>
</dependency>
</dependencies>
</dependencyManagement>
docker-compose
version: "3.8"
services:
login-service:
container_name: login-service-container
image: springboot-app-login
restart: always
build: ./login-service
ports:
- "8082:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:mysql://login_db_docker_image:3306/loginservice
SPRING_DATASOURCE_USERNAME: root
SPRING_DATASOURCE_PASSWORD: secret
SPRING_JPA_HIBERNATE_DDL_AUTO: update
depends_on:
login_db_docker_image:
condition: service_healthy
login_db_docker_image:
container_name: login_db_docker_image
image: mysql:latest
volumes:
- ./login_db_docker_image/mysql_volume_login:/var/lib/mysql
- ./login_db_docker_image/loginservice.sql:/docker-entrypoint-initdb.d/loginservice.sql
ports:
- "3308:3306"
environment:
MYSQL_DATABASE: loginservice
MYSQL_ROOT_PASSWORD: secret
healthcheck:
test: [ "CMD-SHELL", "mysqladmin ping -h localhost -u root -psecret" ]
interval: 10s
timeout: 5s
retries: 5
employee-service:
container_name: employee-service-container
image: springboot-app-employee
restart: always
build: ./employee-service
ports:
- "8084:8080"
environment:
SPRING_DATASOURCE_URL: jdbc:postgresql://employee_db_docker_image:5432/employee
SPRING_DATASOURCE_USERNAME: postgres
SPRING_DATASOURCE_PASSWORD: secret
SPRING_JPA_HIBERNATE_DDL_AUTO: update
depends_on:
employee_db_docker_image:
condition: service_healthy
employee_db_docker_image:
container_name: employee_db_docker_image
image: postgres:latest
volumes:
- ./employee_db_docker_image/postgres_employeeDB_vol:/var/lib/postgresql/data
- ./employee_db_docker_image/employee.sql:/docker-entrypoint-initdb.d/employee.sql
restart: always
ports:
- "5432:5432"
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: secret
POSTGRES_DB: employee
healthcheck:
test: [ "CMD-SHELL", "pg_isready -U postgres" ]
interval: 10s
timeout: 5s
retries: 5
eureka-server:
image: springcloud/eureka:latest
container_name: eureka-server-container
ports:
- "8761:8761"
environment:
- SPRING_PROFILES_ACTIVE=docker
volumes:
mysql_volume_login:
init.sql:
postgres_employeeDB_vol:
driver: local
networks:
network1:
name: microservices-network
external: true
error found in eureka container:
ERROR 1 --- [ main] c.c.c.ConfigServicePropertySourceLocator : Could not locate PropertySource: I/O error on GET request for "http://localhost:8888/eureka/docker":Connection refused; nested exception is java.net.ConnectException: Connection refused
I'm not sure why it's looking for eureka on port 8888 unless that's the default for docker.
looking at stack i cannot find a answer that solves this problem, i am stuck at this. If anyone could help, thank you for advance.
I'm migrating my reverse proxy from zuul to spring cloud gateway (oauth2), i search and read Spring documentation and other topics about this subject but i can't understand what's missing. When i try to get a page, i get the login page from my authentication manager (ok), i enter my user and password (it checks and get 200) and then instead of redirecting to the previous page i get this :
"java.lang.IllegalStateException: No provider found for class org.springframework.security.oauth2.client.authentication.OAuth2AuthorizationCodeAuthenticationToken
at org.springframework.security.web.server.authentication.AuthenticationWebFilter.lambda$authenticate$4(AuthenticationWebFilter.java:100) ~[spring-security-web-5.1.13.RELEASE.jar:5.1.13.RELEASE]
[...]"
This is my yml for authentication server:
client:
registration:
auth_provider:
client-id: service
client-secret: service-secret
scopes: openid,read,write
authorization-grant-type: authorization_code
redirectUriTemplate: http://localhost:9010/login/oauth2/code/{registrationId}
provider:
auth_provider:
authorization-uri: http://localhost:9010/api/auth_provider/oauth/authorize
token-uri: http://localhost:9010/api/auth_provider/token
user-info-uri: http://localhost:9010/api/auth_provider/oauth/users/extra
And the routes (resume):
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
default-filters:
- TokenRelay
routes:
- id: auth_provider
uri: lb://auth_provider/
predicates:
- Path=/api/auth_provider/**
- id: my_service
uri: lb://my_service/
predicates:
- Path=/ui/my_service/**
This is my Security Configuration (resume):
#Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
// Require authentication for all requests (allow login screen)
http
.authorizeExchange()
.pathMatchers("/api/auth_provider/**", "/login**", "/login?error**", "/login?logout**", "/logout").permitAll()
.anyExchange().authenticated();
// Authenticate through configured OpenID Provider
http.oauth2Login();
//JWT Resource Server
http.oauth2ResourceServer().jwt();
http.csrf().disable();
return http.build();
}
And the pom:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!-- Token Relay -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
</dependency>
<!-- http.oauth2ResourceServer().jwt() -->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-jose</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>
If anyone have this problemas and could help, thank you very much.
I'm using Spring Cloud(Hoxton.SR10) with Spring Boot (2.2.6.RELEASE)
I registre my services in Eureka server 8761
and I have a gateway-service to manage routing (without any security for the moment)
# profil DEV
---
spring:
profiles: dev
cloud:
gateway:
routes:
- id: pr-api-id
uri: http://localhost:8086/
predicates:
- Path=/api/**
and this is the pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- Spring cloud eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
when I call localhost:9092/api/v0 (I have a service on localhost:8086/v0 that working fine) should return me the same result of localhost:8086/v0 du to the routing of spring cloud gateway
but I got http error 404
This application has no explicit mapping for /error, so you are seeing this as a fallback.
Mon Sep 27 12:46:20 CEST 2021
There was an unexpected error (type=Not Found, status=404).
No message available
gateway mainClass java
#SpringBootApplication
#EnableEurekaClient
public class GatewayApplication {
I finally resolve my problem by adding the cors-configuration in my config file.
spring:
cloud:
gateway:
default-filters:
- DedupeResponseHeader=Access-Control-Allow-Origin
globalcors:
cors-configurations:
"[/**]":
allowCredentials: true
allowedOrigins: "*"
allowedHeaders: "Origin, X-Requested-With, Content-Type, Accept, Content-Length, TOKEN, Authorization"
allowedMethods: "GET, POST, PATCH, PUT, DELETE, OPTIONS"
maxAge: 3628800
I have a scenario with spring boot, zuul as the gateway, and Eureka as Service discovery. I need to implement the retry mechanism before doing the fallback in the gateway. But the retry code is not working.Applcation.yml is given below
server:
port: 8080
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8083/eureka
spring:
application:
name: gateway-service
zuul:
retryable: true
prefix: /api
routes:
test-service:
sensitive-headers: Cookie,Set-Cookie
service-id: test-service
path: /testservice/**
strip-prefix: true
retryable: true
test-service:
ribbon:
MaxAutoRetries: 5
retryableStatusCodes: 503
OkToRetryOnAllOperations: true
authorization:
token:
name: Authorization
prefix: Bearer
secret: qqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
hystrix:
command:
test-service:
execution:
isolation:
strategy: THREAD
thread:
timeoutInMilliseconds: 60000000
timeout:
enable: false
app:
auth:
allowPermissionPaths:
- /
- /error
- /favicon.ico
- /**/*.png
- /**/*.gif
- /**/*.svg
- /**/*.jpg
- /**/*.html
- /**/*.css
- /**/*.sass
- /**/*.js
- /api/testservice/**
the pom.xml adding below
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-ribbon -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
I am expecting help to implement the retry with zuul gateway.
I'm trying to create a Spring cloud microservice application using Zuul and Consul.
I have 2 components in my project:
api-gateway microservice using Zuul
Hello world microservice (a simple hello world Rest Webservice)
Here is the code of The api-gateway:
#SpringBootApplication
#EnableZuulProxy
#EnableDiscoveryClient
public class ZuulApplication {
public static void main(String[] args) {
SpringApplication.run(ZuulApplication.class, args);
}
}
The pom.xml
<parent>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>Brixton.M3</version>
</parent>
<properties>
<java.version>1.8</java.version>
<spring.cloud.consul.version>1.0.0.M4</spring.cloud.consul.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-commons</artifactId>
</dependency>
<dependency>
<!-- Setup Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<!-- Setup Spring MVC & REST, use Embedded Tomcat -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<dependency>
<!-- Spring Cloud starter -->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zuul</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-all</artifactId>
<version>${spring.cloud.consul.version}</version>
</dependency>
</dependencies>
application.yml
zuul:
routes:
hello1:
path: /hello1/**
serviceId: microservice-example
logging:
level:
org.springframework: INFO
com.netflix: DEBUG
bootstrap.yml
spring:
application:
name: edge-server
cloud:
consul:
config:
enabled: true
host: localhost
port: 8500
Here is the code of hello microservice:
#SpringBootApplication
#EnableConfigServer
#EnableDiscoveryClient
#RestController
public class Application {
#RequestMapping(value="/hello1",method = RequestMethod.GET)
public String hello() {
System.out.print("hello1");
return "Hello1";
}
public static void main(String[] args) {
new SpringApplicationBuilder(Application.class).web(true).run(args);
}
}
bootstrap.yml:
spring:
application:
name: microservice-example
profiles:
active: native
cloud:
consul:
config:
enabled: true
host: localhost
port: 8500
But, when I start the api-gateway I got the following exception:
Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.cloud.netflix.zuul.filters.RouteLocator]: Factory method 'routeLocator' threw exception; nested exception is java.lang.IllegalStateException: Unable to locate service in consul agent: edge-server
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588) ~[spring-beans-4.2.3.RELEASE.jar:4.2.3.RELEASE]
... 69 common frames omitted
Caused by: java.lang.IllegalStateException: Unable to locate service in consul agent: edge-server
at org.springframework.cloud.consul.discovery.ConsulDiscoveryClient.getLocalServiceInstance(ConsulDiscoveryClient.java:66) ~[spring-cloud-consul-discovery-1.0.0.M4.jar:1.0.0.M4]
This issue is fixed in Brixton.M3 (1.0.0.M5). As mentioned above this was an issue with spring-cloud-consul. The new version is working fine