ZUUL gateway path mapping gateway degradation filter

Posted by stelthius on Sun, 07 Nov 2021 23:38:35 +0100

ZUUL gateway

Gateway = = forwarding. When accessing services in the future, you don't need to access the address of each service every time. You only need to access the gateway

It is mainly used for request splitting, message merging and protocol conversion

Note: before version E, you can directly access http:localhost: / / port number / routes or filter

From version H, you need to access http:localhost: / / port number / Actor / routes or filter

pom.xml

<span style="background-color:#f8f8f8"><span style="color:#333333">​
            <span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>org.springframework.cloud<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>spring-cloud-starter-netflix-zuul<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
​
            <span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
<span style="color:#Aa5500 "> <! -- you need a password to access eureka's page -- ></span>
            <span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>org.springframework.boot<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>spring-boot-starter-security<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
            <span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
<span style="color:#aa5500"><!-- Pull the service list through eureka -- ></span>
            <span style="color:#117700"><</span><span style="color:#117700">dependency</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>org.springframework.cloud<span style="color:#117700"></</span><span style="color:#117700">groupId</span><span style="color:#117700">></span>
                <span style="color:#117700"><</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>spring-cloud-starter-netflix-eureka-client<span style="color:#117700"></</span><span style="color:#117700">artifactId</span><span style="color:#117700">></span>
​
            <span style="color:#117700"></</span><span style="color:#117700">dependency</span><span style="color:#117700">></span></span></span>

application.yml

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">server</span><span style="color:#555555">:</span>
<span style="color:#221199">  port</span><span style="color:#555555">: </span><span style="color:#116644">16500</span>
<span style="color:#221199">eureka</span><span style="color:#555555">: </span><span style="color:#aa5500">#The address of the registry to get a list of services</span>
<span style="color:#221199">  client</span><span style="color:#555555">:</span>
<span style="color:#221199">    service-url</span><span style="color:#555555">:</span>
<span style="color:#221199">      defaultZone</span><span style="color:#555555">: </span>http<span style="color:#555555">:</span>//zhangsan<span style="color:#555555">:</span> abc@localhost < span style = "color: #555555" >: < / span > 10000 / Eureka < span style = "color: #aa5500" > #curl style</span>
​
<span style="color:#221199">spring</span><span style="color:#555555">:</span>
<span style="color:#221199">  application</span><span style="color:#555555">:</span>
<span style="color:#221199">    name</span><span style="color:#555555">: </span>22apigateway-zuul
<span style="color:#221199">  security</span><span style="color:#555555">:</span>
<span style="color:#221199">    user</span><span style="color:#555555">:</span>
<span style="color:#221199">      password</span><span style="color:#555555">: </span>xiaomei
<span style="color:#221199">      name</span><span style="color:#555555">: </span>laowang <span style="color:#aa5500">#The default is user</span>
<span style="color:#221199">management</span><span style="color:#555555">:</span>
<span style="color:#221199">  endpoints</span><span style="color:#555555">:</span>
<span style="color:#221199">    web</span><span style="color:#555555">:</span>
<span style="color:#221199">      exposure</span><span style="color:#555555">:</span>
<span style="color:#221199">        include</span><span style="color:#555555">: </span><span style="color:#aa1111">'*'</span>  <span style="color:#aa5500">#Allow access to all management addresses, otherwise you cannot view the routing list page / Actor / routes through the web page, but it does not affect the routing function</span></span></span>

annotation

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@EnableZuulProxy</span></span></span>

Mapping path

Custom mapping path

Because the request name set in our registry may be complex, we can map this address to the address you want to change through the yml file. If multiple domain names need to be modified, write it in the next line

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">zuul</span><span style="color:#555555">:</span>
<span style="color:#221199">  routes</span><span style="color:#555555">:</span>
<span style="color:#221199">    13orderconsumer-openfeign-hytrix</span> <span style="color:#555555">: </span>/jinwandalaohu/**  <span style="color:#aa5500">#To access the 13orderconsumer openfeign hytrix path, you need to access it through jinwandalaohu</span></span></span>

After mapping the request address, we find that the original domain name can also be accessed. If we don't want to access the previous address, we need to add a list of ignored services in the yml file

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">zuul</span><span style="color:#555555">:</span>
<span style="color:#221199">  routes</span><span style="color:#555555">:</span>
<span style="color:#221199">    13orderconsumer-openfeign-hytrix</span> <span style="color:#555555">: </span>/jinwandalaohu/**  <span style="color:#aa5500">#To access the 13orderconsumer openfeign hytrix path, you need to access it through jinwandalaohu</span>
<span style="color:#221199">    itemprovider-eureka-hystrix</span> <span style="color:#555555">: </span>/laohubanichile/**
<span style="color:#221199">  ignored-services</span><span style="color:#555555">:</span>
    13orderconsumer-openfeign-hytrix , itemprovider-eureka-hystrix  <span style="color:#aa5500">#Add a list of ignored services. Multiple services are separated by. If all services are ignored, write '*'</span></span></span>

Mapping clusters of other services

In the actual development, our service nodes are all clusters. When a service cluster is not registered on eureka, we need to configure it separately

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">zuul</span><span style="color:#555555">:</span>
<span style="color:#221199">  routes</span><span style="color:#555555">:</span>
<span style="color:#221199">    aaaaa</span><span style="color:#555555">: </span><span style="color:#aa5500">#Write freely, but it cannot be repeated in the configuration file</span>
<span style="color:#221199">      path</span><span style="color:#555555">: </span>/abcdefg/** <span style="color:#aa5500">#Mapped address</span>
<span style="color:#221199">      serviceId</span><span style="color:#555555">: </span>05consumer-eureka <span style="color:#aa5500">#Which service do you want to set the routing address for</span>
<span style="color:#221199">    bbbb</span><span style="color:#555555">:</span>
<span style="color:#221199">      path</span><span style="color:#555555">: </span>/def/**
<span style="color:#221199">      serviceId</span><span style="color:#555555">: </span>04provider-eureka</span></span>

Same prefix

Like the controller, we can also give the same prefix to the address in zuul, just set it in the yml file

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#221199">zuul</span><span style="color:#555555">:</span>
<span style="color:#221199">    prefix</span><span style="color:#555555">: </span>/suibian</span></span>

Expression mapping (grayscale Publishing)

When we upgrade the service, the corresponding interfaces may be different due to different versions (gray publishing = = > there will be two different version services at the same time). In order to facilitate access, our gateway provides an expression method to facilitate our operation

<span style="background-color:#f8f8f8"><span style="color:#333333"> <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Set the service mapping method. When the name of our service is name VX, the access address will be mapped to VX / name</span>
     <span style="color:#aa5500">* Generally, we will distinguish versions in this way</span>
     <span style="color:#aa5500">* For example, if a service is called gouwuche-v1, its path is V1 / gouwuche</span>
     <span style="color:#aa5500">* When our service is upgraded, we only need to change the name to gouwuche-v2, so the client can access different versions of the service through different version prefixes</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Bean</span>
    <span style="color:#770088">public</span> <span style="color:#000000">PatternServiceRouteMapper</span> <span style="color:#0000ff">serviceRouteMapper</span>() {
      <span style="color:#Aa5500 "> / / where < name > < version > is an alias that corresponds to the content of the expression. In fact, name represents ^. That is, any content < version > represents v. represents the content starting with V, so the following expression represents name VX</span>
        <span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">PatternServiceRouteMapper</span>(
                <span style="color:#aa1111">"(?<name>^.+)-(?<version>v.+$)"</span>,
                <span style="color:#aa1111">"${version}/${name}"</span>);
    }</span></span>

Gateway degradation

When the gateway is abnormal, you can also implement fallback degradation, implement the FallbackProvider interface, and rewrite the methods according to the actual business requirements

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Component</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">MyFallbackProvider</span> <span style="color:#770088">implements</span> <span style="color:#000000">FallbackProvider</span> {
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Which service is the current fallback for? If it is all classes, return '*'</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getRoute</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"*"</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">*</span>
     <span style="color:#aa5500">* @param route Specific problem services</span>
     <span style="color:#aa5500">* @param cause Causes of problems</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#000000">ClientHttpResponse</span> <span style="color:#000000">fallbackResponse</span>(<span style="color:#008855">String</span> <span style="color:#000000">route</span>, <span style="color:#000000">Throwable</span> <span style="color:#000000">cause</span>) {
        <span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">ClientHttpResponse</span>() {
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#000000">HttpStatus</span> <span style="color:#000000">getStatusCode</span>() <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
                <span style="color:#770088">return</span> <span style="color:#000000">HttpStatus</span>.<span style="color:#000000">OK</span>;<span style="color:#Aa5500 "> / / return the corresponding value according to the actual situation of your business</span>
            }
​
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">getRawStatusCode</span>() <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
                <span style="color:#770088">return</span> <span style="color:#116644">200</span>;<span style="color:#Aa5500 "> / / status code</span>
            }
​
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getStatusText</span>() <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
                <span style="color:#770088">return</span> <span style="color:#Aa1111 ">" returns "< / span >" as appropriate;
            }
​
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#008855">void</span> <span style="color:#000000">close</span>() {
​
            }
​
            <span style="color:#aa5500">/**</span>
             <span style="color:#aa5500">*</span>
             <span style="color:#aa5500">* @return  The content we want to return is returned through the io stream</span>
             <span style="color:#aa5500">* @throws IOException</span>
             <span style="color:#aa5500">*/</span>
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#000000">InputStream</span> <span style="color:#000000">getBody</span>() <span style="color:#770088">throws</span> <span style="color:#000000">IOException</span> {
                <span style="color:#770088">return</span> <span style="color:#770088">new</span> <span style="color:#000000">ByteArrayInputStream</span>(<span style="color:#aa1111">"What? No"</span>.<span style="color:#000000">getBytes</span>(<span style="color:#000000">StandardCharsets</span>.<span style="color:#000000">UTF_8</span>));
            }
​
            <span style="color:#aa5500">/**</span>
             <span style="color:#aa5500">* Response header</span>
             <span style="color:#aa5500">* @return</span>
             <span style="color:#aa5500">*/</span>
            <span style="color:#555555">@Override</span>
            <span style="color:#770088">public</span> <span style="color:#000000">HttpHeaders</span> <span style="color:#000000">getHeaders</span>() {
                <span style="color:#000000">HttpHeaders</span> <span style="color:#000000">httpHeaders</span> <span style="color:#981a1a">=</span> <span style="color:#770088">new</span> <span style="color:#000000">HttpHeaders</span>();
                <span style="color:#000000">httpHeaders</span>.<span style="color:#000000">add</span>(<span style="color:#aa1111">"Content-Type"</span>,<span style="color:#aa1111">"text/html;charset=utf-8"</span>);
                <span style="color:#770088">return</span> <span style="color:#000000">httpHeaders</span>;
            }
        };
    }
}</span></span>

error address translation

When an exception occurs in our service, spring provides us with an error address. We can map this address to our own and return the content we show the user

Whitelabel Error Page
This application has no explicit mapping for /error, so you are seeing this as a fallback.Sun Nov 07 14:29:38 CST 2021
There was an unexpected error (type=Not Found, status=404).
 

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@RestController</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">ErrorController</span> <span style="color:#770088">implements</span> <span style="color:#000000">org</span>.<span style="color:#000000">springframework</span>.<span style="color:#000000">boot</span>.<span style="color:#000000">web</span>.<span style="color:#000000">servlet</span>.<span style="color:#000000">error</span>.<span style="color:#000000">ErrorController</span> {
    <span style="color:#555555">@PostMapping</span>(<span style="color:#000000">value</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"/error"</span>,<span style="color:#000000">produces</span> <span style="color:#981a1a">=</span> <span style="color:#aa1111">"text/html;charset=utf-8"</span>)
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">processError</span>(){
        <span style="color:#770088">return</span> <span style="color:#Aa1111 ">" your computer has a major problem, Salem sent it to me "< / span >;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">*Which address should we replace? The return value will map to our own address instead of spring's own</span>
     <span style="color:#aa5500">* In version 2.3.0 and before, to implement this method, you can not implement this method after 2.3.0, and the system will automatically map it to ours</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">getErrorPath</span>() {
        <span style="color:#770088">return</span> <span style="color:#aa1111">"/error"</span>;<span style="color:#Aa5500 "> / / replace this address</span>
    }
}</span></span>


Filter

The gateway provides us with a filter filter for batch operations, such as obtaining requests, interrupting requests, returning results, etc

As long as we implement the ZuuFilter interface and rewrite the methods inside, we can implement the filter function

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#555555">@Component</span>
<span style="color:#770088">public</span> <span style="color:#770088">class</span> <span style="color:#0000ff">MyPreFilter</span> <span style="color:#770088">extends</span> <span style="color:#000000">ZuulFilter</span> {
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Type of current filter</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">String</span> <span style="color:#000000">filterType</span>() {
        <span style="color:#770088">return</span> <span style="color:#000000">FilterConstants</span>.<span style="color:#000000">PRE_TYPE</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Filter order. In the case of the same type, the smaller the number, the higher the priority</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">int</span> <span style="color:#000000">filterOrder</span>() {
        <span style="color:#770088">return</span> <span style="color:#116644">0</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* Whether the current filter is on</span>
     <span style="color:#aa5500">* Here, you can decide whether to open it according to the actual business requirements</span>
     <span style="color:#aa5500">* false Not open</span>
     <span style="color:#aa5500">* @return</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">boolean</span> <span style="color:#000000">shouldFilter</span>() {
        <span style="color:#770088">return</span> <span style="color:#221199">false</span>;
    }
​
    <span style="color:#aa5500">/**</span>
     <span style="color:#aa5500">* This is done if the filter is on</span>
     <span style="color:#aa5500">* @return Meaningless because it does not return the user's</span>
     <span style="color:#aa5500">* @throws ZuulException</span>
     <span style="color:#aa5500">*/</span>
    <span style="color:#555555">@Override</span>
    <span style="color:#770088">public</span> <span style="color:#008855">Object</span> <span style="color:#000000">run</span>() <span style="color:#770088">throws</span> <span style="color:#000000">ZuulException</span> {
        <span style="color:#770088">return</span> <span style="color:#221199">null</span>;
    }
}</span></span>

By looking at the source code, we find that zuul provides us with pre filter_ TYPE  , Back end filter POST_TYPE, route filter_ Type, error filter, ERROR_TYPE  , We select the filter we need according to the requirements. In the case of the same type, the smaller the number returned by the filterOrder() method, the higher the priority

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#Aa5500 "> / / todo if the filter requires forced forwarding service, the order of the filter must be greater than or equal to 5, because there are other filters in zuul that will be encapsulated. After I force the change, some data will not be obtained</span></span></span>

The filter also provides us with some encapsulated methods:

<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#000000">RequestContext</span> <span style="color:#000000">requestContext</span> <span style="color:#981a1a">=</span> <span style="color:#000000">RequestContext</span>.<span style="color:#000000">getCurrentContext</span>();
<span style="color:#000000">HttpServletRequest</span> <span style="color:#000000">request</span> <span style="color:#981a1a">=</span> <span style="color:#000000">requestContext</span>.<span style="color:#000000">getRequest</span>();<span style="color:#Aa5500 "> / / get request</span>
<span style="color:#000000">HttpServletResponse</span> <span style="color:#000000">response</span> <span style="color:#981a1a">=</span> <span style="color:#000000">requestContext</span>.<span style="color:#000000">getResponse</span>();<span style="color:#Aa5500 "> / / get response</span>
<span style="color:#008855">String</span> <span style="color:#000000">requestURI</span> <span style="color:#981a1a">=</span> <span style="color:#000000">request</span>.<span style="color:#000000">getRequestURI</span>();<span style="color:#Aa5500 "> / / get the URI of the request</span>
<span style="color:#000000">System</span>.<span style="color:#000000">err</span>.<span style="color:#000000">println</span>(<span style="color:#000000">requestURI</span>);
<span style="color:#Aa5500 "> / / pre notification can interrupt the operation of the request</span>
<span style="color:#aa5500">//requestContext.setSendZuulResponse(false);// Intercept request</span>
<span style="color:#Aa5500 "> / / set the returned result after interception</span>
<span style="color:#000000">response</span>.<span style="color:#000000">setContentType</span>(<span style="color:#aa1111">"text/html;charset=utf-8"</span>);
<span style="color:#000000">requestContext</span>.<span style="color:#000000">put</span>(<span style="color:#aa1111">"suibian"</span>, <span style="color:#Aa1111 ">" content returned after interception "< / span >)</ span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333"><span style="color:#Aa5500 "> / / pre notification can interrupt the operation of the request</span>
<span style="color:#aa5500">//requestContext.setSendZuulResponse(false);// Intercept request</span></span></span>
<span style="background-color:#f8f8f8"><span style="color:#333333">   <span style="color:#000000">requestContext</span>.<span style="color:#000000">put</span>(<span style="color:#000000">FilterConstants</span>.<span style="color:#000000">SERVICE_ID_KEY</span>, <span style="color:#aa1111">"12itemprovider-eureka-hystrix"</span>);<span style="color:#Aa5500 "> / / which service will the current request be forcibly forwarded to</span>
<span style="color:#aa5500">//     requestContext.put(FilterConstants.REQUEST_URI_KEY, "/items/item/test1");// Which address in the above service is forced to forward to</span></span></span>

Topics: Java gateway