Introduction to SpringCloud (5) Zuul

Introduction to SpringCloud (5) Zuul

Many online resources explain the API gateway, what it is, and what it can do very clearly, but for beginners, I think it is not friendly enough. Zuul is the gateway in SpringCloud microservices.

For beginners, you only need to know that Zuul is to perform a unified management on the API when the number of services increases. A certain type of API will call a certain type of service, and in addition to the request The API performs a filter. One step further is Zuul's other functions. The specific functions are shown in the figure:

This article focuses on routing and filtering .

1 How to introduce Zuul

Similarly, to create a Zuul module, there is no consumer side in this example, so the previous method of creating an empty parent module and then creating a specific submodule was not adopted. Then add dependencies to the pom file in Zuul:

< Dependencies > < dependency > < the groupId > </the groupId > < the artifactId > Spring-Cloud-Starter-Netflix-Zuul </the artifactId > </dependency > </Dependencies > copy the code

Up to now, the directory structure of the entire project is as shown in the figure:

2 Main startup class and configuration file

Because it does not involve service consumption, etc., it only handles api processing, so the main startup class is relatively simple

@SpringBootApplication @EnableZuulProxy //Enable Zuul @EnableEurekaClient public class ZuulMain9401 { public static void main (String[] args) {, args); } } Copy code

The configuration file is the same as the regular Eureka client

spring: application: name: zuul9401 server: port: 9401 eureka: client: fetch-registry: true register-with-eureka: true service-url: defaultZone: http://localhost:8001/eureka/ instance: instance-id: zuul9401 copy the code

3 routing and forwarding

Routing and forwarding are mainly modified through configuration files. Add content to the above configuration files . The following three ways of forwarding routing will be discussed.

Set up the service id of registered Eureka

Adding the first wave of configuration files is the addition of the following content to the original configuration files.

Zuul: routes: User-A: path: /API-A/** the serviceId: Eureka-Provide duplicated code

Is defined casually ,
Is the path of external access, serviceId is the microservice configuration file

So the overall meaning of the configuration file added above is that when external access

When the path is related, it will be forwarded to the name
The service provides services.

Open Eureka Service Registration Center

,service providers
, API Gateway

Then visit http://localhost:9401/api-a/eureka/provide. According to the analysis, it should be forwarded to the eureka/provide path in the `eureka-provide` service.

To prevent confusion, post the code of the first project once. For details, please see the first article in this series.

@SpringBootApplication @RestController @EnableEurekaClient public class EurekaProvide7001 { @Value("${server.port}") int port; @GetMapping("/eureka/provide") public String getInfo () { return "hello, i am eureka provide, the provide service. My port: " + port; } @GetMapping("/eureka/delayProvide") public String delayGetInfo () throws InterruptedException { Thread.sleep( 3000 ); return "hello, delay to do something" ; } public static void main (String[] args) {, args); } } Copy code

You can see that the route can be successfully forwarded


Add the second wave of configuration files

Zuul: routes: # User-A: # path:/API-A/** # the serviceId: Provide Eureka- User-B: path: /API-B/** URL: HTTP://localhost: 7101/ Copy Code

Other as above,

Which service needs to be forwarded to


Edit Configurations
Change the port and service name to simulate the new service . The specific operation also has a clear gif in the first article.

Other services do not need to be closed, continue to open the newly created

, Restart
Service, visit http://localhost:9401/api-b/eureka/provide, you can also see successful forwarding

Set the service id of non-registered Eureka

When learning Ribbon before, I also said that we can access some services that are not registered in Eureka through the Ribbon settings , and the same effect can be achieved by setting Ribbon through the configuration file on the API gateway.

Add third wave configuration file

zuul: routes: # user-a: # path:/api-a/** # serviceId: eureka-provide # user-b: # path:/api-b/** # url: http://localhost:7101/ user-c: path: /api-c/** serviceId: provide-without-eureka #This must be necessary ribbon: eureka: enabled: false provide-without-eureka: ribbon: ServerListClassName: listOfServers: localhost:7201, localhost:7202 ConnectTimeout: 1000 ReadTimeout: 3000 MaxTotalHttpConnections: 500 MaxConnectionsPerHost: 100 copy code

If cancel

Relevant notes, access to user-a cannot be forwarded at this time, and an error of 500 will be reported, I guess it is because of the setting
ribbon.eureka.enabled = false
For the sake of.

serviceId is also the name of the microservice, and then set this microservice, so it is set

Microservice name [provid-without-eureka].ribbon
, Other attributes are related attributes, the most important is also
, Which means that this service name will be allocated in these service lists.

For simplicity or use the same service, use the above method to modify the configuration file, modify the port number 7201, modify

eureka.client.register.with.eureka = false
To simulate a service that is not registered in Eureka.

Then copy the configuration again, and change the port number to 7202. In total, two services with ports 7201 and 7202 have been created .

Other services do not need to be turned off, open

Service, restart
Services, at this time all services are opened as follows

Visit http://localhost:9401/api-c/eureka/provide, the service can still be successfully forwarded

4 View routing status

By the way, simply check the routing status. First of all, you still need to add a configuration file, so it must be added.

Management: Endpoints: Web: Exposure: the include: "*" Endpoint: Health: Show-the Details: ALWAYS copy the code

Then visit http://localhost:9401/actuator/routes, the following will appear under normal circumstances

If you want to get detailed information, then just visit http://localhost:9401/actuator/routes/details

5 Fallback when forwarding routes

With Hystrix, when the forwarding route finds that the service cannot provide the service normally, it can fallback.

Create a new class


@Component public class MyFallbackProvider implements FallbackProvider { @Override public String getRoute () { //Provide fallback for all routes return "*" ; } @Override public ClientHttpResponse fallbackResponse (String route, Throwable throwable) { return new ClientHttpResponse() { @Override public HttpStatus getStatusCode () throws IOException { return HttpStatus.OK; } @Override public int getRawStatusCode () throws IOException { return 200 ; } @Override public String getStatusText () throws IOException { return "OK" ; } @Override public void close () { } @Override public InputStream getBody () throws IOException { //rollback displayed return new new ByteArrayInputStream ( "something Wrong, fallback now" .getBytes ()); } @Override public HttpHeaders getHeaders () { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.APPLICATION_JSON); return headers; } }; } } Copy code

Now let's close it manually

The service simulates the service downtime, let's see if it can be rolled back

6 filter

The reason Zuul can complete authentication, authorization, static resource processing, etc., is due to the filters described below, but mainly the most basic filtering, which may be discussed in depth in the future.

Create filter

First create the filter package, and then create a filter class

, Needs to be implemented

public class MyPreFilter extends ZuulFilter { @Override public String filterType () { //filter type return FilterConstants.PRE_TYPE; //pre-request processing } @Override public int filterOrder () { //Filter order, the smaller the priority return 0 ; } @Override public boolean shouldFilter () { //Whether to enable filtering return true ; } @Override public Object run () throws ZuulException { //Execute logic RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); System.out.println( "[ PreFilter" + "]" + String.format( "send %s request to %s" ,request.getMethod(),request.getRequestURL())); return null ; } } Copy code


A series of constants are defined in the class, among which for the filter are the following

public static final String ERROR_TYPE = "error" ; //Execute public static final String POST_TYPE = "post" ; //Request public static final String PRE_TYPE = "pre" ; //Request public static final String ROUTE_TYPE before request = "route" ; //Process the target request copy code

At the same time create a post request

public class MyPostFilter extends ZuulFilter { @Override public String filterType () { return FilterConstants.POST_TYPE; } @Override public int filterOrder () { return 0 ; } @Override public boolean shouldFilter () { return true ; } @Override public Object run () throws ZuulException { RequestContext currentContext = RequestContext.getCurrentContext(); HttpServletRequest request = currentContext.getRequest(); //Change PreFilter to PostFilter System.out.println( "[ PostFilter" + "]" + String.format( "send %s request to %s" ,request.getMethod(),request.getRequestURL())) ; return null ; } } Copy code

Inject into the container

Create a new config package and create a class under the package


@Configuration public class ZuulConfiguration { @Bean public MyPreFilter getZuulPreFilterBean () { return new MyPreFilter(); } @Bean public MyPostFilter getZuulPostFilterBean () { return new MyPostFilter(); } } Copy code

At this time, the directory structure of the Zuul module is as follows

Note that there is a pit here, that is, when the filter is turned on, you will find that the fallback in the previous section is invalid.


Service, and clear the idea output console

If the content is then one of the above, then the time should be forwarded is a non-registered into the Eureka service routes

Visit http://localhost:9401/api-c/eureka/provide to view the console output

Creation is not easy, if it is helpful to you, please like, bookmark and share!