related

  1. Spring Cloud Series 1 – Service Registration and Discovery Eureka

  2. Spring Cloud – Client calls Rest + Ribbon

  3. Spring Cloud Combat Series iii – Declarative client Feign

  4. Spring Cloud Series iv – Fuse Hystrix

  5. Spring Cloud Combat Series 5 – Service Gateway Zuul

  6. Spring Cloud Deployment Series (6) – Distributed Configuration center Spring Cloud Config

  7. Spring Cloud Combat Series (7) – Service Link Tracking Spring Cloud Sleuth

  8. Spring Cloud Combat Series (8) – Micro service monitoring Spring Boot Admin

  9. Spring Cloud OAuth 2.0

  10. Single sign-on JWT and Spring Security OAuth

preface

Zuul is an open source API Gateway server for Netflix, which is essentially a Servlet-based Web application. In the microservices framework Spring Cloud, Zuul acts as a gateway to the service and preprocesses requests such as security validation, dynamic routing, load distribution, and so on.

The body of the

1. Route gateway

Create a new service-zuul project module and configure pom.xml as follows:

<? The XML version = "1.0" encoding = "utf-8"? > < project XMLNS = "http://maven.apache.org/POM/4.0.0" XMLNS: xsi = "http://www.w3.org/2001/XMLSchema-instance" Xsi: schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" > < modelVersion > 4.0.0 < / modelVersion > < the parent > < groupId > org. Springframework. Boot < / groupId > The < artifactId > spring - the boot - starter - parent < / artifactId > < version > 1.5.3. RELEASE < / version > < relativePath / > <! -- lookup parent from repository --> </parent> <groupId>io.github.ostenant.springcloud</groupId> < artifactId > service - zuul < / artifactId > < version > 0.0.1 - the SNAPSHOT < / version > < name > service - zuul < / name > < description > Demo Project for Spring Boot</description> <properties> <java.version>1.8</java.version> <spring-cloud.version>Dalston.SR1</spring-cloud.version> </properties> <dependencies> <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> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId>  <scope>test</scope> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>Copy the code

On the application startup class, use the @enableZuulProxy annotation to enable the routing gateway:

@EnableZuulProxy
@EnableEurekaClient
@SpringBootApplication
public class ServiceZuulApplication {

    public static void main(String[] args) { SpringApplication.run(ServiceZuulApplication.class, args); }}Copy the code

Configure the mapping between URL prefixes and services in the application.yml file. First specify the address of a service registry for http://localhost:8761/eureka/, the service of the port number is 8769. The service name is service-zuul. Requests prefixed with /api-a/ are forwarded to service-Feign, and requests prefixed with /api-b/ are forwarded to service-ribbon.

server:
  port: 8769
spring:
  application:
    name: service-zuul
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
zuul:
  routes:
    api-a:
      path: /api-a/**
      serviceId: service-feign
    api-b:
      path: /api-b/**
      serviceId: service-ribbon
Copy the code

Run eureka-Server, Service-HI, service-ribbon, service-Feign, and Service-Zuul in sequence, and start two service-HI service instances on ports 8762 and 8763.

Go to http://localhost:8769/api-a/hi? Name =zuul twice, the server returns the following data:

Hi zuul, I am from port: 8763

Hi zuul, I am from port: 8762

This indicates that Zuul acts as a route. If there are multiple instances of a service, Zuul uses the Ribbon to load balance requests and route them to different service instances.

2. Configure a filter

Zuul is not only used as routing, but also provides filtering capabilities, including some security validation. Continue the renovation project and add a filter provided by Zuul.

@Component
public class MyFilter extends ZuulFilter {
    private Logger logger = LoggerFactory.getLogger(getClass());

    @Override
    public String filterType(a) {
        return "pre";
    }

    @Override
    public int filterOrder(a) {
        return 0;
    }


    @Override
    public boolean shouldFilter(a) {
        return true;
    }

    /** * Filter logic */
    @Override
    public Object run(a) {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        logger.info(String.format("%s >> %s", request.getMethod(), 
                request.getRequestURL().toString()));

        Object accessToken = request.getParameter("token");
        if (accessToken == null) {
            log.warn("token is empty");
            ctx.setSendZuulResponse(false);
            ctx.setResponseStatusCode(401);
            try {
                ctx.getResponse().getWriter().write("token is empty");
            } catch (Exception e) {
                logger.error(e);
                return null; }}return null; }}Copy the code

The filterType() method represents the type of filter:

  • Pre: indicates before a route occurs.

  • Routing: when a route occurs.

  • Post: after a route occurs.

  • Error: sends an error call.

Go to http://localhost:8769/api-b/hi? Name =zuul, the server returns the following response data:

token is empty

Go to http://localhost:8769/api-b/hi? Name =zuul&token=123 Twice, the server returns the following response data:

Hi zuul, I am from port: 8763

Hi zuul, I am from port: 8762

3. Set the API stamp version number

Zuul engineering application on it. On the basis of yml increased a configuration Zuul prefix: / v1, and then restart the application, visit http://localhost:8769/v1/api-b/hi? Name = mark&token = 123.

4. Configure fuses

ZuulFallbackProvider (ZuulFallbackProvider, ZuulFallbackProvider, ZuulFallbackProvider)

@Component
public class MyFallbackProvider implements ZuulFallbackProvider {

    @Override
    public String getRoute(a) {
        return "service-feign";
    }

    @Override
    public ClientHttpResponse fallbackResponse(a) {
        return new ClientHttpResponse() {
            @Override
            public HttpStatus getStatusCode(a) throws IOException {
                return HttpStatus.OK;
            }

            @Override
            public int getRawStatusCode(a) throws IOException {
                return 200;
            }

            @Override
            public String getStatusText(a) throws IOException {
                return "OK";
            }

            @Override
            public void close(a) {}@Override
            public InputStream getBody(a) throws IOException {
                return new ByteArrayInputStream("Fallback method is invoked!".getBytes());
            }

            @Override
            public HttpHeaders getHeaders(a) {
                HttpHeaders httpHeaders = new HttpHeaders();
                httpHeaders.setContentType(MediaType.APPLICATION_JSON);
                returnhttpHeaders; }}; }}Copy the code
  • GetRoute () : specifies which services the fuse works on;

  • FallbackResponse () : Specifies the response data to be returned when fusing.

Restart the service – zuul applications, and close all the service instance of the service – hi, on the browser to http://localhost:8769/v1/api-a/hi? Name =mark&token=123, the server returns the following response data:

Fallback method is invoked!

If you want all routing services to have fuses, simply return the wildcard of “*” on the getRoute() method.

5. Common use of Zuul

Zuul uses a one-step blocking model that performs worse than Nginx, and it’s easy to implement load balancing, smart routing, and fuses because Zuul works seamlessly with other Netflix components. In most cases, Zuul is deployed as a cluster.

  • For different end users, different Zuul is used for routing. For example, mobile terminals share one Zuul gateway instance, Web terminals use another Zuul gateway instance, and other clients use another Zuul instance for routing.

  • Another common cluster deployment approach is load balancing through the combination of Nginx and Zuul.

reference

  • An In-depth Understanding of Spring Cloud and Microservice Construction by Zhipeng Fang

Welcome to pay attention to the technical public number: Zero one Technology Stack

This account will continue to share learning materials and articles on back-end technologies, including virtual machine basics, multithreaded programming, high-performance frameworks, asynchronous, caching and messaging middleware, distributed and microservices, architecture learning and progression.