Spring Cloud Gateway interview questions and practical skills, microservice gateway project case

Microservice Series Navigation

1. What is a microservice gateway

Spring Cloud Gateway is an official gateway developed by Spring based on technologies such as Spring 5.x, Spring Boot 2.0 and Project Reactor. Spring Cloud Gateway aims to provide a simple and effective unified API routing management method for microservice architecture. As a gateway in the Spring Cloud ecosystem , Spring Cloud Gateway aims to replace Netflix Zuul , which not only provides a unified routing method, but also provides basic functions of the gateway based on the Filter chain, such as: security, monitoring/metrics and elasticity.

2. Supporting Features

  • Based on Spring Framework 5, Project Reactor and Spring Boot 2.0
  • dynamic routing
  • Predicates and Filters act on specific routes
  • Circuit breaker integration
  • 集成 Spring Cloud DiscoveryClient
  • Easy to write Predicates and Filters
  • Limiting
  • path rewrite

3. Working principle

The following diagram provides a high-level overview of how Spring Cloud Gateway works:

The client makes a request to Spring Cloud Gateway. Then find the route that matches the request in the Gateway Handler Mapping and send it to the Gateway Web Handler. Handler then sends the request to our actual service to execute business logic through the specified filter chain, and then returns.

Filters are separated by dashed lines because filters may execute business logic before (pre) or after (post) the proxy request is sent.

4. Interview questions

4.1 Comparison of filters and gateways

  • Filter: Intercept control of requests from a single server
  • Gateway: Intercept control of all server requests

4.2 Comparison of zuul and spring cloud gateway

  • zuul: It is from Netflix. It is implemented based on servlet. It is a blocking api and does not support long connections.
  • gateway: It is a micro-service gateway developed by springcloud itself. It is based on Spring5 and can implement responsive non-blocking Api and support long connections.

4.3 The difference between gateway and nginx

  • The same point: all can achieve the interception of api interface, load balancing, reverse proxy, request filtering, etc., can achieve the same effect as the gateway.

  • difference:

  1. Nginx is written in C language, and Gateway is written in Java language, which can better allow us to use java language to process requests.
  2. Nginx is a server-side load balancer.
  3. Gateway is an on-premises load balancer.

4.4 Composition of gateway

  • Routing: The basic module of the gateway, consisting of an ID, a target URI, a set of assertions and a set of filters
  • Assertion: is the access rule for accessing the tour, which can be used to match any content from http requests, such as headers or parameters
  • Filter: This is the filter we usually talk about. It is used to filter some requests. The gateway has its own default filter. Please refer to the official website for details. We can also customize the filter, but we need to implement two interfaces, ordered and globalfilter.

5. Project combat

5.1 MateCloud project source code

project GITHUB Code cloud
MateCloud backend source code https://github.com/matevip/matecloud https://gitee.com/matevip/matecloud
Artemis front-end source code https://github.com/matevip/artemis https://gitee.com/matevip/artemis

5.2 Core dependencies

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
</dependency>

Notice:

  • Spring Cloud Gateway does not use Web as the server, but uses WebFlux as the server. The Gateway project already depends on starter-webflux, so don't rely on starter-web here
  • Since functions such as filters still require Servlet support, we also need to rely on javax.servlet:javax.servlet-api

Address: https://gitee.com/matevip/matecloud/blob/dev/mate-gateway/pom.xml

5.3 Gateway Unified Authentication

package vip.mate.gateway.filter;

import io.jsonwebtoken.Claims;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import vip.mate.core.cloud.props.MateApiProperties;
import vip.mate.core.common.constant.MateConstant;
import vip.mate.core.common.constant.Oauth2Constant;
import vip.mate.core.common.util.ResponseUtil;
import vip.mate.core.common.util.SecurityUtil;
import vip.mate.core.common.util.StringPool;
import vip.mate.core.common.util.TokenUtil;
import vip.mate.core.redis.core.RedisService;

/**
 * 网关统一的token验证
 *
 * @author pangu
 * @since 1.5.8
 */
@Slf4j
@Component
@AllArgsConstructor
public class PreUaaFilter implements GlobalFilter, Ordered {

	private final MateApiProperties mateApiProperties;

	private final RedisService redisService;

	/**
	 * 路径前缀以/mate开头,如mate-system
	 */
	public static final String PATH_PREFIX = "/mate";

	/**
	 * 索引自1开头检索,跳过第一个字符就是检索的字符的问题
	 */
	public static final int FROM_INDEX = 1;

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		// 如果未启用网关验证,则跳过
		if (!mateApiProperties.getEnable()) {
			return chain.filter(exchange);
		}

		// 如果在忽略的url里,则跳过
		String path = replacePrefix(exchange.getRequest().getURI().getPath());
		String requestUrl = exchange.getRequest().getURI().getRawPath();
		if (ignore(path) || ignore(requestUrl)) {
			return chain.filter(exchange);
		}

		// 验证token是否有效
		ServerHttpResponse resp = exchange.getResponse();
		String headerToken = exchange.getRequest().getHeaders().getFirst(Oauth2Constant.HEADER_TOKEN);
		if (headerToken == null) {
			return unauthorized(resp, "没有携带Token信息!");
		}
		String token = TokenUtil.getToken(headerToken);
		Claims claims = SecurityUtil.getClaims(token);
		if (claims == null) {
			return unauthorized(resp, "token已过期或验证不正确!");
		}

		// 判断token是否存在于redis,对于只允许一台设备场景适用。
		// 如只允许一台设备登录,需要在登录成功后,查询key是否存在,如存在,则删除此key,提供思路。
		boolean hasKey = redisService.hasKey("auth:" + token);
		log.debug("查询token是否存在: " + hasKey);
		if (!hasKey) {
			return unauthorized(resp, "登录超时,请重新登录");
		}
		return chain.filter(exchange);
	}

	/**
	 * 检查是否忽略url
	 * @param path 路径
	 * @return boolean
	 */
	private boolean ignore(String path) {
		return mateApiProperties.getIgnoreUrl().stream()
				.map(url -> url.replace("/**", ""))
				.anyMatch(path::startsWith);
	}

	/**
	 * 移除模块前缀
	 * @param path 路径
	 * @return String
	 */
	private String replacePrefix(String path) {
		if (path.startsWith(PATH_PREFIX)) {
			return path.substring(path.indexOf(StringPool.SLASH, FROM_INDEX));
		}
		return path;
	}

	private Mono<Void> unauthorized(ServerHttpResponse resp, String msg) {
		return ResponseUtil.webFluxResponseWriter(resp, MateConstant.JSON_UTF8, HttpStatus.UNAUTHORIZED, msg); }

	@Override
	public int getOrder() {
		return MateConstant.MATE_UAA_FILTER_ORDER;
	}

}

5.4 Gateway Dynamic Routing

package vip.mate.gateway.service.impl;

import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.event.RefreshRoutesEvent;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;

/**
 * 动态更新路由网关service
 * 1)实现一个Spring提供的事件推送接口ApplicationEventPublisherAware
 * 2)提供动态路由的基础方法,可通过获取bean操作该类的方法。该类提供新增路由、更新路由、删除路由,然后实现发布的功能。
 * @author pangu
 */
@Slf4j
@Service
@AllArgsConstructor
public class DynamicRouteServiceImpl implements ApplicationEventPublisherAware {

    private final RouteDefinitionWriter routeDefinitionWriter;

    /**
     * 发布事件
     */
    private ApplicationEventPublisher publisher;

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
        this.publisher = applicationEventPublisher;
    }

    /**
     * 删除路由
     * @param id
     * @return
     */
    public String delete(String id) {
        try {
            log.info("gateway delete route id {}",id);
            this.routeDefinitionWriter.delete(Mono.just(id));
            return "delete success";
        } catch (Exception e) {
            return "delete fail";
        }
    }

    /**
     * 更新路由
     * @param definition
     * @return
     */
    public String update(RouteDefinition definition) {
        try {
            log.info("gateway update route {}",definition);
            this.routeDefinitionWriter.delete(Mono.just(definition.getId()));
        } catch (Exception e) {
            return "update fail,not find route  routeId: "+definition.getId();
        }
        try {
            routeDefinitionWriter.save(Mono.just(definition)).subscribe();
            this.publisher.publishEvent(new RefreshRoutesEvent(this));
            return "success";
        } catch (Exception e) {
            return "update route fail";
        }
    }

    /**
     * 增加路由
     * @param definition
     * @return
     */
    public String add(RouteDefinition definition) {
        log.info("gateway add route {}",definition);
        routeDefinitionWriter.save(Mono.just(definition)).subscribe();
        this.publisher.publishEvent(new RefreshRoutesEvent(this));
        return "success";
    }
}

6. Write at the end

For more functions of the gateway, you can check the official documentation: https://docs.spring.io/spring-cloud-gateway/docs/current/reference/html/ and the actual source code of the gateway of MateCloud, to explore.

A word for you: safe production, everyone is responsible

{{o.name}}
{{m.name}}

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=324052413&siteId=291194637