Server Side Reverse Proxying using Zuul

Technology: Resource routing in an integral part of the micro service architecture. For example, if relative URL is /api/users then the request needs to route to be user service, and if the relative URL is /api/shop then, a request needs to route to shop service.

Zuul is a Java-based Router and server-side load balancer. Spring boot provides a starter for Zuul using this we can easily integrate with it.

Roles of Zuul:

  1. Authentication
  2. Insights
  3. Stress Testing
  4. Canary Testing
  5. Dynamic Routing
  6. Service Migration
  7. Load Shedding
  8. Security
  9. Static Response handling
  10. Active/Active traffic management

Adding Zuul library in spring boot-based applications:

Add the below dependency in pom.xml file:

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-zuul</artifactId> </dependency>

Configure Embedded Zuul Reverse Proxy:

The above maven dependency will create an embedded Zuul reverse proxy to ease the development for micro services where the UI application/ client application want to make access back-end services using Zuul reverse proxy. The back-end services will be deployed on different servers, if we directly invoke these services, need to explicitly manage CORS and authentication problems, these problems will be removed if we use Zuul Reverse proxy.

Enabling Zuul Proxy:

Annotate a Spring Boot main class with @EnableZuulProxy, then based on zuul.routes key URL all requests are passed to specified URL. If we use serviced instead of URL then based on request path all requests, it will have routed to specified service.

Example: zuul.routes.server.url=http://localhost:8090

Suppose if the configure the like above, all request coming http://:/ server will be routed to http://localhost:8090 application.

To forward a request to other micro-services we need to pass configuration to Zuul, the routes that should watch and forward the requests to other services. We specify routes using properties under zuul.routes. Each of our micro services can have an entrance below zuul.routes.NAME, where NAME is the application name (as stored in the spring.application.name property).

If we observe the above example server is the spring.application.name property for one of the spring boot application.

So, if the request comes /server then it will be forwarded to mention URL by passing necessary information like authorization related etc.…

if we include spring-cloud-starter-Netflix-zuul dependency into our project, then by default Ribbon will perform client-side load balancing, also server List will get from Service Discovery provided by Netflix Eureka Server. If we want to disable load balancer at a client, we need to disable Ribbon using below the property.

ribbon.eureka.enabled = false

Then Ribbon will not use Service discovery, only specified Server will be used always.

If we are using inside Eureka then we can specify the service discover id instead of URL of the service application.

Zuul HTTP Client:

By default, Zuul will use Apache HTTPClient as default HTTPClient, instead of Ribbon RestClient, but using the configuration we can either configure OKHTTPClient or Restclient.

Configure ribbon.restclient.enabled=true we want to use Restclient,

ribbon.okhttp.enabled=true if we want to use OkHttpclient.

We can also specify custom Httpclient by creating the bean of type ClosableHttpClient or OkHttpClient.

Cookies and Sensitive Headers:

If the client and server hosted on the same system, it is probably safe to share the cookies between microservices, but it is not recommended to share the cookies if they are hosted on different servers.

We can specify a list of ignored headers as part of the route configuration. If proxy defines cookies and all back-end solutions are part of the similar system, it can be natural to simply share them. In the chain of micro-services if the downstream of the micro-services set some cookies to response then it will be ignored by default if we want to pass to the caller we need to specify as Set-Cookie then it will be passed to the caller.

Example:

zuul: routes: users: path: /myusers/** sensitiveHeaders: Cookie,Set-Cookie,Authorization url: https://downstream

Zuul filters:

Zuul provides 4 standard types of filters.

  1. pre filters are explored before the send is routed,
  2. route filters can manage the accurate routing of the request,
  3. post filters are conducted after the send has been routed, and
  4. Error filters execute if an error occurs during managing the request.

Sample pre filters will look like below:

importcom.netflix.zuul.ZuulFilter; importcom.netflix.zuul.context.RequestContext; importcom.netflix.zuul.exception.ZuulException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; importorg.springframework.stereotype.Component; importjavax.servlet.http.HttpServletRequest; @Component public class SimplePreFilter extends ZuulFilter { private static Logger log = LoggerFactory.getLogger(SimplePreFilter.class); @Override public String filterType() { return "pre"; } @Override publicintfilterOrder() { return 1; } @Override publicbooleanshouldFilter() { return true; } @Override public Object run() throws ZuulException { RequestContextctx = RequestContext.getCurrentContext(); HttpServletRequest request = ctx.getRequest(); log.info(String.format("%s request to %s", request.getMethod(), request.getRequestURL().toString())); return null; } } filterType() will return type of the filter type in this case it is “pre” filterOder(): it gives order of execution relative to others. shouldFilter(): it provides whether we should execute the filter or not. run(): will contain the logic.

Zuul filters collect request and state detail in (and share it by means of) the RequestContext.

We can get the HttpServletRequest from RequestContext object, and logging method and current url of the request before it is sending on the way.

Server Application Main class:

@SpringBootApplication @RestController public class ServerApplication { @RequestMapping(value = "/available") public String available() { return "Spring Boot in Action avaiable"; } @RequestMapping(value = "/checked-out") public String checkedOut() { return "Spring Boot in Action checkout"; } public static void main(String[] args) { SpringApplication.run(ServerApplication.class, args); } }

Client Application main class:

@SpringBootApplication @EnableZuulProxy public class ClientApplication { public static void main(String[] args) { SpringApplication.run(ClientApplication.class, args); } }

Client configuration:

zuul.routes.server.url=http://localhost:8090 ribbon.eureka.enabled=false server.port=8080

If we start both applications and access http://localhost:8080/server/available link in browsers then we can see the response coming from server service.

We can observe the below log in client service

2018-08-25 23:27:04.066 INFO 3744 --- [nio-8080-exec-2] o.s.c.n.zuul.web.ZuulHandlerMapping :

Mapped URL path [/server/**] onto handler of type [class org.springframework.cloud.netflix.zuul.web.ZuulController]

2018-08-25 23:27:04.417 INFO 3744 --- [nio-8080-exec-2] com.example.client.SimplePreFilter : GET request to http://localhost:8080/server/available

We can observe that client is invoking another services-based regex using Zuul.

Conclusion:

Zuul is the library used to provide the reverse proxy, based on the route it will forward to configure URL or service-id by passing the necessary information.If you are looking forward to making a Java web application, Hire Java Developers from Best Java Development Company and get the best solutions for your business.

For information about the source code, click here.