Search code examples
javaregexspring-bootspring-cloudspring-cloud-gateway

SpringCloudGateway - routing issue with duplicate service name in URL


I'm trying to implement a API-Gateway service over our project using Spring-Cloud-Gateway.

Consider that I have a service named admin and I'm trying to configure it's route as below:

spring:
  application:
    name: gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true
          lower-case-service-id: true
      routes:
        - id: admin_route
          uri: lb://admin
          predicates:
            - Path=/admin/**

It compiles successfully but there is just a problem!!

I have an API on admin service with a URL like below that works fine without a gateway:

http://localhost:<ADMIN_PORT>/admin/system/employee/check

But when I want to call this API through gateway service, I have to duplicate the admin in the URL, like below, so that it works fine:

http://localhost:<GATEWAY_PORT>/admin/admin/system/employee/check 

Does anybody have any idea or clue how to resolve this issue?

Any help would be appreciated!!

Note: Spring-Boot 2.7.0, Soring-Cloud 2021.0.3, Java 1.8

******************** UPDATE ************************

I have set servlet-context-path and apllication.name in admin's application.yml as below:

spring:
  application:
    name: admin
server:
  port: <ADMIN_PORT>
  servlet:
    context-path: /admin

I think that it is the reason why I need to duplicate the service name in the URL, But I couldn't find any configuration on SpringCloudGateway related to this topic!!

******************** ATTENTION ************************

I am not allowed to remove servlet-context-path which has been set to /admin from admin's application.yml, because I need them to call my services internally without getting help from Gateway!!

So I need the following URL:

http://localhost:<GATEWAY_PORT>/admin/system/employee/check

to be routed to the following address:

http://localhost:<ADMIN_PORT>/admin/system/employee/check

without /admin getting removed after routing!!

Still, any help would be appreciated!!! :))


Solution

  • the culprit is this config:

      cloud:
        gateway:
          discovery:
            locator:
              enabled: true
    

    from docs:

    8.2 DiscoveryClient Route Definition Locator The Gateway can be configured to create routes based on services registered with a DiscoveryClient compatible service registry.

    To enable this, set spring.cloud.gateway.discovery.locator.enabled=true and make sure a DiscoveryClient implementation is on the classpath and enabled (such as Netflix Eureka, Consul or Zookeeper).

    8.2.1 Configuring Predicates and Filters For DiscoveryClient Routes By default the Gateway defines a single predicate and filter for routes created via a DiscoveryClient.

    The default predicate is a path predicate defined with the pattern /serviceId/**, where serviceId is the id of the service from the DiscoveryClient.

    The default filter is rewrite path filter with the regex /serviceId/(?.*) and the replacement /${remaining}. This just strips the service id from the path before the request is sent downstream.

    so when you call the following URL:

    http://localhost:<GATEWAY_PORT>/admin/system/employee/check 
    

    the gateway rewrite the path to /system/employee/check, because admin is the service name.

    when you call :

    http://localhost:<GATEWAY_PORT>/admin/admin/system/employee/check 
    

    the gateway rewrite the path to /admin/system/employee/check, which is the correct one.