What is an API gateway

API Gateway is the entrance of all requests, carrying all traffic, API Gateway is a portal, can also be said to be the only node into the system. This is much like the Facet pattern in the object-oriented design pattern. The API Gateway encapsulates the architecture of the internal system and provides apis to individual clients. It may also have other capabilities such as authorization, monitoring, load balancing, caching, request sharding and management, static response processing, and so on

The API Gateway is responsible for request forwarding, composition, and protocol transformation. All requests from clients are routed through the API Gateway and then routed to the corresponding microservice. The API Gateway will often process a request and aggregate the results of multiple services by invoking multiple microservices. It can convert between Web protocols and non-Web-friendly protocols used internally, such as HTTP and WebSocket.

The diagram shows that without the gateway, the client requests will directly fall into the back-end services and cannot be centrally managed.In the case of a gateway, all requests pass through the gateway and then are distributed to the corresponding service

2. Importance of API gateways

API gateways are important in microservice projects, providing a unified management and scheduling between services

Reference nginx official of a high quality blog, www.nginx.com/blog/buildi… , the example introduces a complex e-commerce system, which is designed according to the micro-service theory and has the following services:

  • Shopping cart service: Number of items in a shopping cart
  • Order service: Order history
  • Catalog services: Basic product information, such as its name, image, and price
  • Audit service: customer audit
  • Inventory service: Low inventory warning
  • Shipping service: Shipping options, terms and costs are extracted separately from the shipping provider’s API
  • Recommendation service: Suggested items

In the absence of a gateway, the client invokes each service directly:Ideally, individual service invocations would work normally, but as the business grows and the calls between services become more complex, the system would look like this:If there is no unified management, it is certainly not reasonable, so the gateway can be introduced as a unified portal, as shown in the figure:

3. The role of API Gateway

Ok, after a brief introduction to the gateway, I want to talk about the functions of the gateway, which is also summarized in the Spring Cloud website:Of course, we can pick a few important introductions ourselves

  • Dynamic routing

The gateway can perform route forwarding. If the service information changes, it only needs to change the gateway configuration. Therefore, the gateway has the function of Dynamic Routing, as shown in the figure:

  • Request to monitor

Request monitoring can monitor requests across the system, logging request responses in detail, as shown in figure 2. Logs can be thrown into message queues, and if gateways are not used, logging request information needs to be done in individual services

  • Certification authentication

Authentication authentication can authenticate each access request, reject illegal requests, protect back-end services, do not need to do authentication for each service, in the project often add OAuth2.0, JWT, Spring Security for permission verification

  • Pressure test

For a system with a gateway, if you want to stress test a service, you can change the gateway configuration as shown in the figure. The test request is routed to the test service, and the test service will have a separate test database, so that the test request will not affect the formal service and database

What is Netflix Zuul?

Netflix Zuul is an API gateway middleware developed by Netflix. Zuul is a LOAD balancer based on JVM routing and server side. It provides routing, monitoring, elasticity, and security services. Zuul works with Eureka, Ribbon, Hystrix and other components to provide a unified API gateway

5. How Netflix Zuul works

referenceZuul website wikiThe core diagram of Zuul is actually a filter. Zuul is implemented based on servlets. When a request comes in, it goes to the Pre filter, and after the Pre filter is done, it goes to the routing filter, and it starts routing to the specific service, and the error is intercepted by the error filter

  • Filter type:
    • PRE FILTER: Perform this operation before routing filters. Capabilities can include requesting authentication, selecting the original server, and logging debugging information.
    • ROUTE FILTER: Handles the process of routing requests to sources. This is where raw HTTP requests are built and sent using Apache HttpClient or Netflix Ribbon.
    • POST FILTER: Executed after the request is routed to the FILTER. Capabilities can include adding standard HTTP headers to the response, collecting statistics and metrics, and transferring the response from the source stream to the client.
    • ERR FILTER: An error FILTER is called when an error occurs in one of the other phases

6. Preparation of Zuul experimental environment

Environment Preparation:

  • JDK 1.8
  • SpringBoot2.2.3
  • SpringCloud(Hoxton.SR6)
  • Maven 3.2 +
  • The development tools
    • IntelliJ IDEA
    • smartGit

To create a SpringBoot Initialize project, please refer to my previous blog: SpringBoot Series of Quick Project creation tutorials

Maven configuration:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        </dependency>
Copy the code

This blog is based on the spring-cloud-starter- Netflix – Eureka -client test, before the test to run eureka server, Eureka service provider, code please refer to the previous chapter blog

After the project is successfully created, add @enableZuulProxy to the startup class:

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.zuul.EnableZuulProxy;

@SpringBootApplication
@EnableZuulProxy
public class SpringcloudZuulApplication {

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

7, Eureka, Zuul configuration

Eureka client configuration:

server:
  port: 8082
This is the serviceId of the microservice registry
spring:
  application:
    name: zuul-api-gateway

eureka:
  client:
  	Service registry URL
    service-url:
      defaultZone: http://localhost:8761/eureka/ 
    Register-with-eureka and fetch-registry are both true
    register-with-eureka: true
    fetch-registry: true
  instance:
    status-page-url-path: http://localhost:8761/actuator/info
    health-check-url-path: http://localhost:8761/actuator/health
    prefer-ip-address: true
    instance-id: zuul-api-gateway8082
Copy the code

Zuul Configuration routing rules:

zuul:
  routes:
    provider: # Route id, you can define it yourself
      service-id: eureka-service-provider Service id(must be configured)
      path: /provider/** The path mapped is the same as routes.provider
      url: http://localhost:8083 The url to which the route is routed may not be configured
Copy the code

Zuul configuration access prefix: we need to add access prefix, eg: http://localhost:8082/api-gateway/provider/api/users/mojombo

zuul:
  # configure prefix
  prefix: /api-gateway
Copy the code

Zuul configure Header filtering:

zuul:
 # configure filter sensitive request headers. Set this parameter to null
  sensitive-headers: Cookie,Set-Cookie,Authorization
Copy the code

Zuul configure redirection to add Host:

zuul:
# redirection adds the host header
  add-proxy-headers: true
Copy the code

Zuul timeout Settings:

zuul:
  host:
    Set connection timeout
    connect-timeout-millis: 15000
    Socker send timeout
    socket-timeout-millis: 60000
Copy the code

Zuul all configuration reference, details refer to the official website:

zuul:
  # configure prefix
  prefix: /api-gateway
  routes:
    provider: # Route id, you can define it yourself
      service-id: eureka-service-provider # service id
      path: /provider/** The path mapped is the same as routes.provider
      url: http://localhost:8083 # route to url
  host:
    Set connection timeout
    connect-timeout-millis: 15000
    Socker send timeout
    socket-timeout-millis: 60000
  Request URL encoding
  decode-url: true
  # query string encoding
  force-original-query-string-encoding: false
  # configure filter sensitive request headers. Set this parameter to null
  sensitive-headers: Cookie,Set-Cookie,Authorization
  # redirection adds the host header
  add-proxy-headers: true
Copy the code

Visit: http://localhost:8082/api-gateway/provider/api/users/mojombo, to add a prefix, configuration of the path

Possible errors encountered, 504 errors:

After troubleshooting, the timeout setting needs to be added, because the call service timed out, resulting in error 504

zuul:
  host:
    connect-timeout-millis: 15000
    socket-timeout-millis: 60000
Copy the code

With the configuration, the service was successfully invoked

8, Zuul custom filter

In the previous introduction, several filters were introduced. Now you customize the implementation of these four filters

Ps: Spring Cloud also provides examples of Zuul filters. For details, go to github: github.com/spring-clou…

Project Structure: Filter types reference org.springframework.cloud.net flix. Zuul. Filters. SupportFilterConstants. Java:Implement a pre-filter: intercept request, must bring token, otherwise throw prompt, etc

package com.example.springcloud.zuul.web.filter;

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.FORWARD_TO_KEY;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.SERVICE_ID_KEY;

/** ** <pre> * API gateway prefilter * </pre> ** <pre> *@authorMazq * Modified Record * Modified by: Date: 2020/08/05 18:08 Modified content: * </pre> */
@Slf4j
//@Component
public class ZuulApiGatewayPreFilter extends ZuulFilter {

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

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

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

    @Override
    public Object run(a) throws ZuulException {
        RequestContext ctx = RequestContext.getCurrentContext();
        HttpServletRequest request = ctx.getRequest();
        String accessToken = request.getParameter("token");
        if (StringUtils.isEmpty(accessToken)) {
            // Zuul filters the request without routing it
            ctx.setSendZuulResponse(false);
            // Set the error code returned
            ctx.setResponseStatusCode(403);
            ctx.setResponseBody("AccessToken is Invalid ");
            return null;
        }
        log.info("accessToken: {}",accessToken);
        // Otherwise, services continue
        return null; }}Copy the code

Post filter, often used to print logs and other operations, code reference: www.baeldung.com/zuul-filter… To achieve the effect, after the route filter is executed, the post filter is executed to print logs:

package com.example.springcloud.zuul.web.filter;

import com.google.common.io.CharStreams;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.protocol.RequestContent;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.POST_TYPE;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;

/ * * * < pre > * API Gateway rear-mounted filter * < / pre > < pre > * * *@authorMazq * Modified Record * Modified by: Date: 2020/08/06 10:05 Modified Content: * </pre> */
@Slf4j
//@Component
public class ZuulApiGatewayPostFilter extends ZuulFilter {
    @Override
    public String filterType(a) {
        return POST_TYPE;
    }

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

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

    @Override
    public Object run(a) throws ZuulException {
        RequestContext context = RequestContext.getCurrentContext();
        try (final InputStream responseDataStream = context.getResponseDataStream()) {
            if(responseDataStream == null) {
                log.warn("RESPONSE BODY: {}"."");
                return null;
            }
            String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
            log.info("RESPONSE BODY: {}", responseData);
            context.setResponseBody(responseData);
        }
        catch (Exception e) {
            throw new ZuulException(e, INTERNAL_SERVER_ERROR.value(), e.getMessage());
        }
        return null; }}Copy the code

Register the filter, load the filter into the Spring container, or add @Component to the filter class

package com.example.springcloud.zuul;

import com.example.springcloud.zuul.web.filter.ZuulApiGatewayErrFilter;
import com.example.springcloud.zuul.web.filter.ZuulApiGatewayPostFilter;
import com.example.springcloud.zuul.web.filter.ZuulApiGatewayPreFilter;
import com.example.springcloud.zuul.web.filter.ZuulApiGatewayRouteFilter;
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 SpringcloudZuulApplication {

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

    @Bean
    public ZuulApiGatewayPreFilter zuulApiGatewayPreFilter(a){
        return new ZuulApiGatewayPreFilter();
    }
    @Bean
    public ZuulApiGatewayPostFilter zuulApiGatewayPostFilter(a){
        return new ZuulApiGatewayPostFilter();
    }
    @Bean
    public ZuulApiGatewayRouteFilter zuulApiGatewayRouteFilter(a){
        return new ZuulApiGatewayRouteFilter();
    }
    @Bean
    public ZuulApiGatewayErrFilter zuulApiGatewayErrFilter(a){
        return newZuulApiGatewayErrFilter(); }}Copy the code

Access gateway:http://localhost:8082/api-gateway/provider/api/users/mojombo, not to bring a token http://localhost:8082/api-gateway/provider/api/users/mojombo?token=?, bring a token call success

9. View Zuul routing information

In addition, spring-boot-starter-actuator monitors routing information:

<dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
Copy the code

Spring – the boot – starter – physical configuration:

management:
  endpoints:
    web:
      exposure:
        # Enable monitoring of routes (info,health) by default
        include: info,health,routes
  Enable health check details
  endpoint:
    health:
      show-details: always
Copy the code

Visit http://localhost:8082/actuator/routes for routing, details, SpringBoot2.2.3 version with physical prefix, the call is successful, returns the json data:

{
    "/api-gateway/provider/**":"eureka-service-provider"."/api-gateway/eureka-service-provider/**":"eureka-service-provider"
}
Copy the code

For routing information details, access link: http://localhost:8082/actuator/routes/details

{
    "/api-gateway/provider/**": {"id":"provider"."fullPath":"/api-gateway/provider/**"."location":"eureka-service-provider"."path":"/ * *"."prefix":"/api-gateway/provider"."retryable":false."customSensitiveHeaders":false."prefixStripped":true
    },
    "/api-gateway/eureka-service-provider/**": {"id":"eureka-service-provider"."fullPath":"/api-gateway/eureka-service-provider/**"."location":"eureka-service-provider"."path":"/ * *"."prefix":"/api-gateway/eureka-service-provider"."retryable":false."customSensitiveHeaders":false."prefixStripped":true}}Copy the code

This blog code sample download: code download

Spring Cloud: Spring Cloud: Spring Cloud: Spring Cloud…

Zuul Github Wiki: github.com/Netflix/zuu

Github Zuul filter example: github.com/spring-clou…

Reference for quality learning materials:

  • Nginx website for micro service gateway is introduced: www.nginx.com/blog/buildi…

  • SpringCloud Component Gateway Zuul(Hoxton version):juejin.cn/post/684790…

  • Fang Zhipeng bosses series Spring Cloud blog: www.fangzhipeng.com/spring-clou…

  • Eacdy.gitbooks. IO/Spring-clou…

  • Programmers DD bosses series Spring Cloud blog: blog.didispace.com/spring-clou…