[Chapter 7] Zuul Gateway Service

1.1 Overview

In the microservice architecture, several basic service governance components are required, including service registration and discovery, service consumption, load balancing, circuit breakers, intelligent routing, configuration management , etc. These basic components cooperate with each other to form a Simple microservice system. A simple microservice system is shown below:

insert image description here
Note: AServices and Bservices can call each other, and I forgot when drawing

In Spring Clouda microservice system, a common implementation of load balancing is that the client's request first goes through load balancing (zuul、Ngnix), then reaches the service gateway ( zuulcluster), and then to the specific service. Services are uniformly registered to the high-availability service registry cluster. All configuration files of the service are managed by the configuration service (explained in the next article). The configuration files of the configuration service are placed in the gitwarehouse, which is convenient for developers to change the configuration at any time.

1.2 ZuulDetailed Gateway

1.2.1 What is the significance of gateway

1.2.1.1 Two questions

1. We know that we are going to enter a service itself. Obviously, we have no particularly good way to directly enter the IPaddress + port number . We know that this approach is very bad. This approach is very problematic . IPAddressIP , others will know where the service is deployed by looking at your address, making it easy for others to attack .

2. Second, we have so many services , do we want to call them one by one? We assume that we have done a permission authenticationJVM here. Each of our customers accesses different service programs running on different machines. We Each service requires a service authentication . Is it annoying to do this? Obviously, it is very annoying.

1.2.1.2 Solutions

Then we are faced with these two extremely important problems at this time, and then we need a way to solve them. First of all, let's look at IPthe exposure of the address and IPthe single-point problem caused by the address writing . Do I have to dynamically maintain the list of its services for the service itself? I need to call the service itself, do I also need a load? Balance the same thing.

There is also the thing about IP address exposure , do I need to do a proxy , something like Nginxa reverse proxy, and deploy public modules on this thing, such as the permission verification of all entrances.

So we now need a Zuul APIgateway. It solves the above problem. If you want to call a service, it will map it to you, map the IPaddress of your service to a path, you enter the path, it matches, and it will access the service for you. It will have a request forwarding process , like Nginxthe specific instance of the service machine, it will not access it directly IP, it will go to Eurekathe registry to get the instance IDof the service, that is, the name of the service. Again, I use client-side load balancing Ribbonto access one of the service instances .

APIThe gateway is mainly to solve the problem of how to call the external call of the service itself, and to solve the problem of permission verification . You can integrate and call a series of filters here , such as integration shiro,springsecurityand the like.

insert image description here

ZuulBy loading the dynamic filtering mechanism , the following functions can be achieved:

1. Authentication and security: Identify authentication requirements for various resources and reject those that do not meet the requirements

2. Review and monitoring: Track meaningful data and statistical results at the edge to bring us accurate production status conclusions

3. Dynamic routing: dynamically route requests to different backend clusters as needed

4. Stress test: Gradually increase the load traffic to the cluster to calculate the performance level

5. Load distribution: Allocate the corresponding capacity for each load type, and discard requests that exceed the limit

6. Static response processing: Partial responses are established directly at the edge location to prevent them from flowing into the internal cluster

AWS7. Multi-region resiliency: request routing across regions, aiming to ELBdiversify usage and ensure that edge locations are as close as possible to users

1.3 ZuulCode Examples

The first step is to create a new module under the original project Zuuland introduce dependencies. The code is as follows:

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

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

Then @EnableZuulProxyannotate the startup class with the following code:

server:
  port: 5000
spring:
  application:
    name: api-geteway
zuul:
  routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
    hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
      path: /hello-service/**
#这里一定要是你Eureka注册中心的服务的名称,所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
#如url:http://localhost:8080/  这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
      serviceId: hello-service      
    api-a:
      path: /api-a/**
      serviceId: service-ribbon
    api-b:
      path: /api-b/**
      serviceId: service-feign
eureka:
#客户端
  client:
#注册中心地址
    service-url:
      defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

Description Tip: /hello-service/Requests starting with are forwarded to the hello-serviceservice; /api-a/requests starting with are forwarded to the service-ribbonservice; /api-b/requests starting with are forwarded to the service-feignservice;

Then start the registry and two service providers in the previous article, hello-serviceand then we run to see if its request forwarding function is polled to enter the two services.

Enter localhost:5000/hello-service/helloas follows:

insert image description here
Then refresh it again:

insert image description here
It can be seen zuulthat the request distribution has been carried out. hello-servieIt is mapped to a specific machine according to your service name . Isn't this the function of a reverse proxy ?

zuulRequest filtering can also be performed , so let's perform tokenverification to demonstrate. First, we need to create a new TokenFilterclass to inherit ZuulFilterthis class and implement its four interfaces. The code is as follows:

package hjc.zuul;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import javax.servlet.http.HttpServletRequest;

public class TokenFilter extends ZuulFilter {
    
    
    //四种类型:pre,routing,error,post
    //pre:主要用在路由映射的阶段是寻找路由映射表的
    //routing:具体的路由转发过滤器是在routing路由器,具体的请求转发的时候会调用
    //error:一旦前面的过滤器出错了,会调用error过滤器。
    //post:当routing,error运行完后才会调用该过滤器,是在最后阶段的
    @Override
    public String filterType() {
    
    
        return "pre";
    }

    //自定义过滤器执行的顺序,数值越大越靠后执行,越小就越先执行
    @Override
    public int filterOrder() {
    
    
        return 0;
    }

    //控制过滤器生效不生效,可以在里面写一串逻辑来控制
    @Override
    public boolean shouldFilter() {
    
    
        return true;
    }

    //执行过滤逻辑
    @Override
    public Object run() {
    
    
        RequestContext context = RequestContext.getCurrentContext();
        HttpServletRequest request = context.getRequest();
        String token = request.getParameter("token");
        if (token == null){
    
    
            context.setSendZuulResponse(false);
            context.setResponseStatusCode(401);
            context.setResponseBody("unAuthrized");
            return null;
        }
        return null;
    }
}

filterType: Returns a string representing the type of filter ,
in zuulwhich four filter types with different life cycles are defined, as follows:

1. pre: It can be called before the request is routed. It is used in the routing mapping stage to find the routing mapping table.

2. route: is called when the routing request is made, and the specific routing forwarding filter is called when the routingspecific request of the router is forwarded.

3. error: Called when an error occurs while processing the request

4. post: When routing, errorthe filter will be called after running, which is in the final stage

Here is a statement about zuulthe exception that occurs when the filter executes the network request. The filter cannot directly throw the try-catchcaptured exception to the page. The exception thrown by the application can be returned. The solution is to catchuse the context.set()method to return it to the page. as follows:

try{
    
    
    //业务逻辑......
}catch(Exception e){
    
    
        RequestContext context = RequestContext.getCurrentContext();
          context.set("error.status_code",401);
            context.set("error.exception",e);
            context.set("error.message","sfdfsdf");
}

Next, you also need to add this filter to spring中,让spring` management, the code is as follows:

package hjc;

import hjc.zuul.TokenFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
@EnableZuulProxy
public class ZuulApplication {
    
    

    public static void main(String[] args) {
    
    
        SpringApplication.run(ZuulApplication.class, args);
    }

  //将过滤器交给Spring管理
    @Bean
    public TokenFilter tokenFilter(){
    
    
        return new TokenFilter();
    }

}

Next, let's start the startup class, first without tokenaccess, as follows:

insert image description here

As you can see, returning a message without permission, I want to talk about it here, it Tokenis usually placed in the request header, here we just don’t do that for demonstration. Then it will be tokenbrought back to visit, as follows:

insert image description here

It can be seen that this has already put our request in the past.

Here I also want to talk about what is the default route, zuuldelete the configuration of the routing configuration, as follows:

server:
  port: 5000
spring:
  application:
    name: api-geteway

eureka:
#客户端
  client:
#注册中心地址
    service-url:
      defaultZone: http://localhost:8888/eureka/,http://localhost:8889/eureka/

Then, restart to continue accessing, as follows:

insert image description here

It can be seen that we can still continue to access. We have nothing to match, but we can still access. That is because, by default, your service name is hello-serviceautomatically declared here.

Then, if I don't want it to automatically declare it for me, I want to define it myself, then I can ymluse it in the configuration file to zuu.ignored-servicesfilter myself like a filter, as follows:

zuul:
#如果ignored-services:*  表示所有的默认路由都失效了,要自己一个个配,没人会那么操蛋,除非遇到奇葩业务

  ignored-services: 

Then let's talk about the mapping rules, for example:

zuul:
  routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
    hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
      path: /hello-service/**
#这里一定要是你Eureka注册中心的服务的名称,是所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
#如url:http://localhost:8080/  这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
      serviceId: hello-service

zuul:
  routes:
    hello-service:
      path: /hello-service/ext/**
      serviceId: hello-service

There are two zuulconfiguration mapping paths here /hello-service/. You can see that they /hello-service/**are included /hello-service/ext/**. Is there a conflict when these two paths are matched? How to deal with it? Who will match first?

Here is ymlthe order defined in to match. If it is a application.propertiesformat configuration file, its order cannot be guaranteed. The ymlformat configuration file is in order and can be guaranteed. Pay attention here.

What if we want to define a matching rule? Then we need to define one in the startup class, beanwhich determines your routing, as follows:

insert image description here
I won't demonstrate it here, and you can find the information slowly when you need it.

There is also ignored-patterns:, as follows:

zuul:
  routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
    hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
      path: /hello-service/**
#这里一定要是你Eureka注册中心的服务的名称,是所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
#如url:http://localhost:8080/  这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
      serviceId: hello-service
  ignored-patterns: /hello/**

ignored-patterns: Indicates the shielded /hello/**path , even if you /hello-service/hello/**can't do it, still shield it. We can further refine this configuration. For example, if I don't want to /helloroute the interface, then we can configure it as above.

What if we also want to configure a prefix for a service ? code show as below:

zuul:
  routes:
#标识你服务的名字,这里可以自己定义,一般方便和规范来讲还是跟自己服务的名字一样
    hello-service:
#服务映射的路径,通过这路径就可以从外部访问你的服务了,目的是为了不爆露你机器的IP,面向服务的路由了,给你选一个可用的出来,
#这里zuul是自动依赖hystrix,ribbon的,不是面向单机
      path: /hello-service/**
#这里一定要是你Eureka注册中心的服务的名称,是所以这里配置serviceId因为跟eureka结合了,如果单独使用zuul,那么就必须写自己机器的IP了,
#如url:http://localhost:8080/  这样的不好就是写死IP了,万一这IP挂了,这高可用性,服务注册那套东西就用不起来了
      serviceId: hello-service
  prefix: /api/**

You can see that the services you access must be /api/prefixed, for example/api/hello-service/**

If we still want to make a path access and jump to my local, what should we do?

I hope that users /localcan automatically jump to this method to process when accessing, then Zuulthe local jump we need to use at this time is configured as follows:

zuul:
  prefix: /api
  ignored-patterns: /**/hello/**
  routes:
    local:
      path: /hello-service/**
      url: forward:/local

Some of our commonly used, docking springsecurity, or some third-party components, they will obtain some of your cookieinformation, then the Zuulgateway will kill all your information for the sake of security cookie, this is no way to do cookieit, it is killed by default .

Here is Zuulprovided zuul.sensitive-headersto do this for you cookie, headerdo not filter this information, control your sensitive information.

By default, sensitive header information cannot be passed through the APIgateway, we can make it pass through the following configuration:

zuul:
  routes:
    hello-service:
      path: /hello-service/**
      serviceId: hello-service
  sensitive-headers:   cookie,header之类额东西

It can also be used with Hystrixsome detailed configurations, which have been mentioned earlier. I won't say it here

Guess you like

Origin blog.csdn.net/weixin_42039228/article/details/123758035