Spring Cloud to Go – How to incorporate a Go service in the Spring Cloud Stack
Spring Cloud – Web context root aware Zuul Eureka service calls [code bit]
Making Zuul proxy aware of your microservices’ web context root and avoid adding the context on the proxy url
Eureka does not support microservice web context roots out of the box (just yet?). To avoid adding these contexts to your Zuul proxy requests you can extend the RibbonRoutingFilter and use the service homepage URL to pick up the context and amend it to the outgoing request. You can do the same for service-to-service calls. I talked about it HERE.
package za.co.webler.zuul.filters; import com.netflix.zuul.ZuulFilter; import com.netflix.zuul.context.RequestContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.cloud.client.ServiceInstance; import org.springframework.cloud.client.discovery.DiscoveryClient; import org.springframework.cloud.netflix.eureka.EurekaDiscoveryClient; import java.net.URI; import java.util.List; import java.util.Objects; public class ContextAwareRibbonRoutingFilter extends ZuulFilter { private static Logger logger = LoggerFactory.getLogger(ContextAwareRibbonRoutingFilter.class); private static final String REQUEST_URI_KEY = "requestURI"; private static final String SERVICE_ID_KEY = "serviceId"; private final DiscoveryClient discoveryClient; public ContextAwareRibbonRoutingFilter(DiscoveryClient discoveryClient) { this.discoveryClient = discoveryClient; } @Override public String filterType() { return "pre"; } @Override public int filterOrder() { return 6; } @Override public boolean shouldFilter() { return true; } /** * Filter to cater for historical issues when running spri * * @return null */ @Override public Object run() { RequestContext context = RequestContext.getCurrentContext(); String requestMethod = context.getRequest().getMethod(); String serviceId = (String) context.get(SERVICE_ID_KEY); String originalContext = (String) context.get(REQUEST_URI_KEY); List<ServiceInstance> instances = discoveryClient.getInstances(serviceId); if (instances.isEmpty()) { return respondNotFound(context); } logger.info("Inbound {} request URL {} for service {}", requestMethod, context.getRequest().getRequestURI(), serviceId); EurekaDiscoveryClient.EurekaServiceInstance chosenInstance = (EurekaDiscoveryClient.EurekaServiceInstance) instances.get(0); String homePageUrl = chosenInstance.getInstanceInfo().getHomePageUrl(); String path = URI.create(homePageUrl).getPath(); String serviceContext = Objects.equals(path, "/") ? "" : path; String contextAwareServiceUrl = serviceContext + originalContext; context.set(REQUEST_URI_KEY, contextAwareServiceUrl); logger.info("Outbound {} request URL {} for service {}", requestMethod, contextAwareServiceUrl, serviceId); return null; } private Object respondNotFound(RequestContext ctx) { ctx.unset(); ctx.getResponse().setContentType("text/html"); ctx.setResponseStatusCode(404); ctx.setSendZuulResponse(false); return null; } }
Remember, all your services need to define their homepage URLs:
eureka: instance: instance-id: ${spring.application.name}:${spring.cloud.client.hostname}:${server.port} status-page-url-path: ${server.context-path}/info health-check-url-path: ${server.context-path}/health home-page-url-path: ${server.context-path:/} client: registerWithEureka: true fetchRegistry: true service-url: defaultZone: http://localhost:9000/service-discovery/eureka/