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 > org.springframework.cloud </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) { SpringApplication.run(ZuulMain9401.class, 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

user-a
Is defined casually ,
path
Is the path of external access, serviceId is the microservice configuration file
spring.application.name
Value.

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

/api-a/
When the path is related, it will be forwarded to the name
eureka-provid
The service provides services.

Open Eureka Service Registration Center

EurekaServer8001
,service providers
EurekaProvide7001/2/3
, API Gateway
ZuulMain9401
:

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) { SpringApplication.run(EurekaProvide7001.class, args); } } Copy code

You can see that the route can be successfully forwarded

Set URL

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,

url
Which service needs to be forwarded to

by

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

Provide7101
, Restart
ZuulMain9401
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: com.netflix.loadbalancer.ConfigurationBasedServerList listOfServers: localhost:7201, localhost:7202 ConnectTimeout: 1000 ReadTimeout: 3000 MaxTotalHttpConnections: 500 MaxConnectionsPerHost: 100 copy code

If cancel

user-a
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
listOfServers
, 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

ProvideWithoutEureka7201/2
Service, restart
ZuulMain9401
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

MyFallbackProvider
achieve
FallbackProvider
interface

@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

ProvideWithoutEureka7201/2
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

MyPreFilter
, Needs to be implemented
ZuulFilter
interface

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

in

FilterConstants
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

ZuulConfiguration

@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.

Reboot

ZuulMain9401
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!