Search code examples
restspring-cloudnetflix-eurekanetflix-zuulapi-gateway

Routing to different services in Zuul over the same API


In my MicroserviceZoo i have a Zuul gateway and 3 Microservices (service1,service2,service3) discovered by Eureka. Zuul shall represent them to the outside and act as api-gateway with loadbalancing (ribbon) and circuit-breaking(hystrix).

Now in the service routing i have a problem which may seem simple to fix, but i am stuck with this far too long.

What i want is that Zuul routes to service1, service2, service3 over the same API:

gateway:port/api/1/service1/public/time 

should become

gateway:port/api/1/public/time

and

gateway:port/api/1/service2/public/stats

shall become

 gateway:port/api/1/public/stats

..such that /api/1/public/stats routes to microservice2 (which hosts the stats method) and /api/1/public/time routes to microservice1 (which hosts the time method)

This is my current Zuul-Config (in bootstrap.yml):

zuul:
  prefix: /api/1
  stripPrefix: false
  routes:
    time:
      path: /**/public/time
      serviceId: service1
    stats:
      path: /**/public/stats
      serviceId: service2
    stream:
      path: /**/public/stream
      serviceId: service3
  ignored-services: '*'
  strip-prefix: false

What am i missing? How do you fine-grained route using Zuul and Eureka?


Solution

  • Answer:

    There is no way to do this easily in Netflix Zuul, as pointed out by Spring Cloud Gateway dev Spencer Gibb

    Unfortunately zuul from spring cloud can only strip prefixes. You want rewrite functionality which is only available in spring cloud gateway unless you write your own filter – spencergibb Jul 13 '19 at 20:37

    The Solution is to switch to Spring Cloud Gateway, which should be easily possible for most deployments of Zuul.

    there you can easily rewrite routes individually, e.g.:

    spring:
      cloud:
        gateway:
         - id: streamservice
              uri: lb://streamservice
              predicates:
                - Path=/stream/**
              filters:
                - RewritePath=/api/(?<streamservice>.*), /$\{streamservice}
         - id: otherservices
              uri: lb://otherservices
              predicates:
                - Path=/otherserviceendpoint
              filters:
                - RewritePath=/api/(?<otherservices>.*), /$\{otherservices}
    

    To achieve the functionality asked in the question, which implied that some services dont get handled by the gateway at all, in cloud gateway define a locator rule to only locate services (via Eureka el al discovery service ) that include "isongateway:true' as metadata in the gateways conf.yml:

      spring:
          cloud:
            gateway:
              discovery:
                locator:
                  include-expression: metadata['isongateway']=='true'
                  enabled: true
    

    so in the services, that should be located & routed by gateway you add the tag to the conf.yml:

    # this is so we can exclude all services that dont have this metadata in gateway
    spring:
      cloud:
        discovery:
          client:
            simple:
              local:
                metadata:
                  isongateway: true
    

    ...and now all other services are not routed by the gateway.