The reverse proxy, load balancer, and fallback fallback of Zuul are studied in the front. This learning to write filters filter, do Java Web development of the filter is not unfamiliar, that is, when the client (such as the browser) to initiate the request, the first through filter filter to do some relevant verification or business judgment (such as login, permissions, etc.), Zuul also provides the filter function. As long as you inherit the Zuulfilter class.
Our first impressions of Zuul are usually as follows: it contains two functions for routing and filtering requests, in which the routing function is responsible for forwarding external requests to specific microservices instances, which is the basis for implementing external access to the unified portal, while the filter function is responsible for intervening the processing of requests. Is the basis of the functions such as request validation and service aggregation.
In fact, however, when the routing function is actually running, its route mapping and request forwarding are done by several different filters. The route map is mainly done by pre-type filters, which match the request path with the configured routing rules to find the destination address to be forwarded, while the part of the request forwarding is done by the route type filter to forward the routing address obtained by the pre type filter.
Therefore, the filter can be said to be Zuul implementation of the API gateway function of the most core components, each incoming Zuul HTTP request will go through a series of filter processing chain to get the request response and return to the client.
Inheriting Zuulfilter.java, some methods need to be implemented
Package com.fei.springcloud.filter;
Import Com.netflix.zuul.ZuulFilter;
public class Testfilter extends zuulfilter{
@Override public
boolean shouldfilter () {
return false;
}
@Override public
Object run () {
return null;
}
@Override public
String FilterType () {
return null;
}
@Override public
int Filterorder () {
return 0;
}
}
Their respective meanings and functions are summarized as follows: FilterType: This function needs to return a string representing the type of the filter, which is the various stages defined during the HTTP request. The four different life cycle filter types are defined by default in Zuul, as follows: Pre: can be called before the request is routed. Routing: Called when a request is routed. Post: Called after the Routing and error filters. Error: Called when a request is processed when a fault occurs. Filterorder: Defines the order in which the filters are executed by an int value, and the smaller the value the higher the priority. Shouldfilter: Returns a Boolean type to determine whether the filter is to be executed. We can use this method to specify the effective range of the filter. Run: The specific logic of the filter. In this function, we can implement the custom filtering logic to determine whether to intercept the current request, not to follow the route, or to do some processing after the request route returns the result.
From the image above, we can see that when an external HTTP request arrives at the API Gateway Service, first it goes to the first stage of the pre, where it is processed by the pre-type filter, and the main purpose of this type of filter is to do some pre-processing before the request is routed, such as the checksum of the request.
After the pre-type filter processing has been completed, the request enters the second phase of routing, which is called the routing request forwarding phase, the request will be processed by the routing type filter, where the specific processing is to forward the external request to the specific service instance process, When the service instance returns the request results, the routing phase completes and the request enters the third stage post, at which point the request is processed by the post type filter, which not only obtains the request information but also obtains the return information of the service instance. So in the Post type filter, we can do some processing or conversion of the processing results.
In addition, there is a special phase error, which is only triggered when an exception occurs in the above three phases, but its final flow is still a post-type filter because it needs to return the final result to the requesting client via the post filter (there are some differences in the actual implementation)
Zuul's own core filter
Under the Spring-cloud-netflix-core-xxx.jar rack package
As shown in the figure above, there are three different life-cycle filters in the filter that is enabled by default, and these filters are very important to help us understand the process of Zuul to external request processing and how we can extend the filter on this basis to complete our own system needs. Below, we will make a detailed introduction to these filters one by one: Pre filter
Servletdetectionfilter: Its execution order is-3, which is the first filter to be executed. The filter is always executed, primarily to detect whether the current request is running through spring's dispatcherservlet processing or through Zuulservlet.
Its test results are stored in the Isdispatcherservletrequest parameter of the current request context in the Boolean type, so that in subsequent filters we can pass the Requestutils.isdispatcherservletrequest () and the Requestutils.iszuulservletrequest () method to determine its implementation to do different processing.
In general, external requests sent to the API gateway are handled by spring's dispatcherservlet, except that requests accessed through the/zuul/path bypass Dispatcherservlet and are processed by Zuulservlet. Mainly used to deal with large file upload situation. In addition, for Zuulservlet access path/zuul/, we can modify it by Zuul.servletpath parameters.
Servlet30wrapperfilter: Its execution order is-2, which is the second filter to execute. The current implementation will take effect for all requests, primarily to wrap the original httpservletrequest into a Servlet30requestwrapper object.
Formbodywrapperfilter: Its execution order is-1, which is the third filter to execute.
The filter takes effect only for two kinds of requests, the first class is content-type for application/x-www-form-urlencoded, and the second class is content-type for multipart/ Form-data and is a request processed by spring's dispatcherservlet (using the results of the servletdetectionfilter processing).
The main purpose of the filter is to wrap the requested body into a Formbodyrequestwrapper object.
Debugfilter: Its execution order is 1, which is the fourth filter to execute.
The filter determines whether the action in the filter is performed based on the configuration parameters zuul.debug.request and the debug parameters in the request. Its specific operation is to set the debugrouting and Debugrequest parameters in the current request context to true.
Because these two values can be accessed in different lifecycles of the same request, we can use these values in subsequent filters to define some debug information so that when there is a problem with the online environment, the debug information can be activated by requesting parameters to help analyze the problem.
In addition, for the debug parameter in the request parameter, we can also use Zuul.debug.parameter to customize.
Predecorationfilter: Its execution order is 5, which is the last filter to be executed in the pre stage. The filter determines whether the forward.to and Serviceid parameters exist in the current request context, and if none exists, it performs the action of the specific filter (if one exists, it indicates that the current request has been processed because the two messages are loaded based on the routing information of the current request).
and its specific operation is to do some preprocessing for the current request, such as: the matching of routing rules, in the context of the request to set the basic information of the request and the route matching results, such as some settings information, such information will be the next filter to deal with the important basis, We can access this information through Requestcontext.getcurrentcontext ().
In addition, we can find some logic to handle HTTP header requests in this implementation, including some familiar header fields, such as: X-forwarded-host, X-forwarded-port.
In addition, the records for these header fields are controlled by the Zuul.addproxyheaders parameter, and this parameter defaults to true, so Zuul adds the x-forwarded-* header field to the request by default when the request jumps. Including: X-forwarded-host, X-forwarded-port, X-forwarded-for, X-forwarded-prefix, X-forwarded-proto.
We can also turn off adding actions to these header fields by setting Zuul.addproxyheaders=false. Route filter Ribbonroutingfilter: Its execution order is 10, which is the first filter to be executed in the route stage. This filter only processes requests that have the Serviceid parameter in the context of the request, that is, only the request to configure the routing rule through Serviceid takes effect. The execution logic of this filter is the core of service-oriented routing, which uses the Ribbon and hystrix to initiate requests to the service instance and returns the result of the service instance's request. Simplehostroutingfilter: Its execution order is 100, which is the second filter to be executed in the route stage. The filter only processes requests that have the Routehost parameter in the context of the request, that is, only the request to configure the routing rule through the URL takes effect. And the execution logic of the filter is directly to the Routehost parameter of the physical address of the request, from the source we can know that the request is directly through the HttpClient package implementation, and not using the Hystrix command to wrap, so such requests are not thread isolation and circuit breaker protection. Sendforwardfilter: Its execution order is 500, which is the third filter to be executed in the route stage. This filter only processes requests that have the forward.to parameter in the context of the request, which is used to handle the forward local jump configuration in the routing rule. Post Filter Senderrorfilter: Its execution order is 0, which is the first filter to be executed in the post phase. The filter is executed only if the request context contains the Error.status_code parameter (the error code set by the previously executed filter) and has not been processed by the filter. The specific logic of the filter is to use the error information in the context of the request to organize a request to forward to the API Gateway/error error endpoint to generate an error response. Sendresponsefilter: Its execution order is 1000, which is the last filter to be executed in the post phase. The filter checks whether the request context contains header information related to the request response, the response data stream, or the response body, and the processing logic is executed only when one of them is included. The processing logic of the filter is to use the response information of the request context to organize the response content that needs to be sent back to the client.
Code combat, full code on GitHub
Write the filter for the filter,1 post type of 2 pre-type. If the first pre-filter validation fails, the subsequent filter does not need to be executed.
Testpre01filter.java
package com.fei.springcloud.filter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
/**
* The first pre type filter, prefilter01=true can pass
* @author Jfei
*
*/
public class TestPre01Filter extends ZuulFilter{
/**
* Whether the filter should be executed, if it is false, the filter is not executed
*/
@Override
public boolean shouldFilter() {
return true;
}
/**
* Filter type
* Sequence: pre ->routing -> post, the error type filter can be triggered when an exception occurs in the above 3 sequences
*/
@Override
public String filterType() {
To
return FilterConstants.PRE_TYPE;
}
/**
* In the same filterType type, the larger the order value, the lower the priority
*/
@Override
public int filterOrder() {
To
return 1;
}
/**
* Perform business operations, execute sql, nosql and other businesses
*/
@Override
public Object run() {
To
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
To
String prefilter01 = request.getParameter("prefilter01");
System.out.println("Execute pre01Filter .....prefilter01=" + prefilter01 );
//If the user name and password are correct, continue to execute the next filter
if("true".equals(prefilter01) ){
ctx.setSendZuulResponse(true);//Routing will be performed, that is, the api service provider will be called
ctx.setResponseStatusCode(200);
ctx.set("isOK",true);//You can put some values in ctx to facilitate subsequent filter acquisition and use
}else{
ctx.setSendZuulResponse(false);//No routing is required, that is, the api service provider will not be called
ctx.setResponseStatusCode(401);
ctx.set("isOK",false);//You can put some values in ctx to facilitate subsequent filter acquisition and use
//Return the content to the client
ctx.setResponseBody("{\"result\":\"pre01Filter auth not correct!\"}");// Return error content
}
return null;
}
To
}
This is the first custom pre-type filter, which says that Shuldfilter () is true, that is, you must perform a
Testpre02filter.java
package com.fei.springcloud.filter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
/**
* prefilter02 check prefilter02=true to pass
* @author Jfei
*
*/
public class TestPre02Filter extends ZuulFilter{
/**
* Whether the filter should be executed, if it is false, the filter is not executed
*/
@Override
public boolean shouldFilter() {
//The last filter set the value
return RequestContext.getCurrentContext().getBoolean("isOK");
}
/**
* Filter type
* Sequence: pre ->routing -> post, the error type filter can be triggered when an exception occurs in the above 3 sequences
*/
@Override
public String filterType() {
To
return FilterConstants.PRE_TYPE;
}
/**
* In the same filterType type, the larger the order value, the lower the priority
*/
@Override
public int filterOrder() {
To
return 2;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
To
String prefilter02 = request.getParameter("prefilter02");
System.out.println("Execute pre02Filter .....prefilter02=" + prefilter02 );
//If the user name and password are correct, continue to execute the next filter
if("true".equals(prefilter02) ){
ctx.setSendZuulResponse(true);//Routing will be performed, that is, the api service provider will be called
ctx.setResponseStatusCode(200);
ctx.set("isOK",true);//You can put some values in ctx to facilitate subsequent filter acquisition and use
}else{
ctx.setSendZuulResponse(false);//No routing is required, that is, the api service provider will not be called
ctx.setResponseStatusCode(401);
ctx.set("isOK",false);//You can put some values in ctx to facilitate subsequent filter acquisition and use
//Return the content to the client
ctx.setResponseBody("{\"result\":\"pre02Filter auth not correct!\"}");// Return error content
}
return null;
}
}
Testpostfilter.java
package com.fei.springcloud.filter;
import javax.servlet.http.HttpServletRequest;
import org.springframework.cloud.netflix.zuul.filters.support.FilterConstants;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
/**
*
* Post type filter, post=true can pass
*
*/
public class TestPostFilter extends ZuulFilter{
/**
* Whether the filter should be executed, if it is false, the filter is not executed
*/
@Override
public boolean shouldFilter() {
//The last filter set the value
return RequestContext.getCurrentContext().getBoolean("isOK");
}
/**
* Filter type
* Sequence: pre ->routing -> post, the error type filter can be triggered when an exception occurs in the above 3 sequences
*/
@Override
public String filterType() {
To
return FilterConstants.ROUTE_TYPE;
}
/**
* In the same filterType type, the larger the order value, the lower the priority
*/
@Override
public int filterOrder() {
To
return 1;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
HttpServletRequest request = ctx.getRequest();
To
String post = request.getParameter("post");
System.out.println("Execute postFilter .....post=" + post );
//If the user name and password are correct, continue to execute the next filter
if("true".equals(post) ){
ctx.setSendZuulResponse(true);//Routing will be performed, that is, the api service provider will be called
ctx.setResponseStatusCode(200);
ctx.set("isOK",true);//You can put some values in ctx to facilitate subsequent filter acquisition and use
}else{
ctx.setSendZuulResponse(false);//No routing is required, that is, the api service provider will not be called
ctx.setResponseStatusCode(401);
ctx.set("isOK",false);//You can put some values in ctx to facilitate subsequent filter acquisition and use
//Return the content to the client
ctx.setResponseBody("{\"result\":\"post auth not correct!\"}");// Return error content
}
return null;
}
}
Start the class and register the filter
Package Com.fei.springcloud;
Import org.springframework.boot.SpringApplication;
Import org.springframework.cloud.client.SpringCloudApplication;
Import Org.springframework.cloud.netflix.zuul.EnableZuulProxy;
Import Org.springframework.context.annotation.Bean;
Import Com.fei.springcloud.filter.TestPre02Filter;
Import Com.fei.springcloud.filter.TestPostFilter;
Import Com.fei.springcloud.filter.TestPre01Filter;
@EnableZuulProxy
@SpringCloudApplication Public
class Zuulfilterapplication {public
static void main ( String[] args) {
springapplication.run (zuulfilterapplication.class, args);
}
@Bean public
Testpre01filter Testpre01filter () {
return new Testpre01filter ();
}
@Bean public
Testpre02filter Testpre02filter () {
return new Testpre02filter ();
}
@Bean public
Testpostfilter Testpostfilter () {
return new Testpostfilter ();
}
}
Start Eureka-server,eureka-api (learned before, also complete code), and then start Zuul-filter,
Browser Request Http://127.0.0.1:8888/user-api/user/find
Http://127.0.0.1:8888/user-api/user/find?prefilter01=true
Http://127.0.0.1:8888/user-api/user/find?prefilter01=true&prefilter02=true
Comparing the contents of the page and the log of the console print, the API microservices will not print if the pre checksum is not available, stating that the API MicroServices are not being invoked and that the post filter does not execute the full code.