springcloud服务网关有什么作用 (基于Spring cloud项目)

介绍

SpringCloud2.x的网关gateway提供了一个在springwebflux之上构建API网关的库。旨在提供一种简单而有效的方法来路由到api,并为它们提供跨领域的关注点,例如:安全性、监视/度量和恢复能力。

spring cloud gateway官网

快速跳转:https://spring.io/projects/spring-cloud-gateway

特色

  1. 基于springframework5.x springboot2.x构建
  2. 支持任意路径、谓词(Predicates)、过滤器(filter)路由匹配,路径重写及定制
  3. 支持熔断处理
  4. 支持spring云客户端(DiscoveryClient)
  5. 支持限速自定义处理

基于springframework5.x springboot2.x构建

增加了如jdk9的运行时支持,及采用了jdk8新特性的开发,如函数式,模块化,响应式编程等内容

支持路由匹配及路径重写

如下:

分别对路径路由,主机路由,重写地址,熔断路由,及熔断回调路由进行了响应的举例。如路径路由的原理为:当网关接收到地址为path_route的请求时将会调向 http://httpbin.org/get方法

@Configeration
public class GatewayConfig {
	@Bean
	public RouteLocator customRoute(RouteLocatorBuilder builder) {
		return builder.routes()
			.route("rount1", r -> r.path("/get")
				.uri("http://httpbin.org"))
			.route("host_route", r -> r.host("*.myhost.org")
				.uri("http://httpbin.org"))
			.route("rewrite_route", r -> r.host("*.rewrite.org")
				.filters(f -> f.rewritePath("/foo/(?<segment>.*)", "/${segment}"))
				.uri("http://httpbin.org"))
			.route("hystrix_route", r -> r.host("*.hystrix.org")
				.filters(f -> f.hystrix(c -> c.setName("slowcmd")))
				.uri("http://httpbin.org"))
			.route("hystrix_fallback_route", r -> r.host("*.hystrixfallback.org")
				.filters(f -> f.hystrix(c -> c.setName("slowcmd").setFallbackUri("forward:/hystrixfallback")))
				.uri("http://httpbin.org"))
			.route("limit_route", r -> r
				.host("*.limited.org").and().path("/anything/**")
				.filters(f -> f.requestRateLimiter(c -> c.setRateLimiter(redisRateLimiter())))
				.uri("http://httpbin.org"))
			.build();
	}
}

支持路由的定制

如下基于redis路由配置的实现,原理是实现RouteDefinitionRepository的保存,删除方法即可对路径的配置进行自定义操作。

import com.springboot.cloud.gateway.service.impl.RouteService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionRepository;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

@Component
@Slf4j
public class RedisRouteRepository implements RouteDefinitionRepository {

    @Autowired
    private RedisRouteService redisRouteService;

    @Override
    public Flux<RouteDefinition> getRouteDefinitions() {
        return Flux.fromIterable(redisRouteService.getRouteDefinitions());
    }

    @Override
    public Mono<Void> save(Mono<RouteDefinition> route) {
        return redisRouteService.save(route);
    }

    @Override
    public Mono<Void> delete(Mono<String> routeId) {
        return redisRouteService.delete(routeId);
    }
}

支持网关级别过滤器的定制

如下,通过实现GlobalFilter接口,实现其filter方法,即可对所有进入网关的请求进行响应的过滤操作,下述代码中主要进行了鉴权的操作。

public class AccessGatewayFilter implements GlobalFilter {

    private final static String X_CLIENT_TOKEN_USER = "x-client-token-user";
    private final static String X_CLIENT_TOKEN = "x-client-token";
    private static final String BEARER = "Bearer";
    /**
     * 由authentication-client模块提供签权的feign客户端
     */
    @Autowired
    private IAuthService authService;

    /**
     * 1.首先网关检查token是否有效,无效直接返回401,不调用签权服务
     * 2.调用签权服务器看是否对该请求有权限,有权限进入下一个filter,没有权限返回401
     *
     * @param exchange
     * @param chain
     * @return
     */
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        String authentication = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
        String method = request.getMethodValue();
        String url = request.getPath().value();
        log.debug("url:{},method:{},headers:{}", url, method, request.getHeaders());
        //不需要网关签权的url
        if (authService.ignoreAuthentication(url)) {
            return chain.filter(exchange);
        }
        // 如果请求未携带token信息, 直接跳出
        if (StringUtils.isBlank(authentication) || !authentication.startsWith(BEARER)) {
            log.debug("url:{},method:{},headers:{}, 请求未携带token信息", url, method, request.getHeaders());
            return unauthorized(exchange);
        }
        //调用签权服务看用户是否有权限,若有权限进入下一个filter
        if (authService.hasPermission(authentication, url, method)) {
            ServerHttpRequest.Builder builder = request.mutate();
            //TODO 转发的请求都加上服务间认证token
            builder.header(X_CLIENT_TOKEN, "TODO zhoutaoo添加服务间简单认证");
            //将jwt token中的用户信息传给服务
            builder.header(X_CLIENT_TOKEN_USER, authService.getJwt(authentication).getClaims());
            return chain.filter(exchange.mutate().request(builder.build()).build());
        }
        return unauthorized(exchange);
    }

    /**
     * 网关拒绝,返回401
     *
     * @param
     */
    private Mono<Void> unauthorized(ServerWebExchange serverWebExchange) {
        serverWebExchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        DataBuffer buffer = serverWebExchange.getResponse()
                .bufferFactory().wrap(HttpStatus.UNAUTHORIZED.getReasonPhrase().getBytes());
        return serverWebExchange.getResponse().writeWith(Flux.just(buffer));
    }
}

支持熔断处理

通过使用注解@EnableCircuitBreaker及配置即可开启熔断处理

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = "com.xgfx.cloud.auth.client")
@EnableCircuitBreaker
@EnableMethodCache(basePackages = "com.xgfx.cloud")
@EnableCreateCacheAnnotation
public class GatewayApplication {
    public static void main(String[] args) {
        SpringApplication.run(GatewayApplication.class, args);
    }
}

支持spring云客户端(DiscoveryClient)

通过使用注解@EnableDiscoveryClient与@EnableFeignClients及配置即可开启spring云处理

支持限流自定义处理

基于分布式缓存redis的限流处理,通过实现RedisRateLimiter,重写isAllowed来验证是否限流

@Configuration
public class CustomRateLimiter extends RedisRateLimiter {

    Config getDefaultConfig() {
        return super.getConfig().get("customRateLimiter");
    }

    public CustomRateLimiter(ReactiveRedisTemplate<String, String> redisTemplate,
                                   RedisScript<List<Long>> script,
                                   @Qualifier("defaultValidator") Validator validator) {
        super(redisTemplate, script, validator);
    }

    @Override
    public Mono<Response> isAllowed(String routeId, String id) {
        if (null == super.getConfig().get(routeId)) {
        		getConfig().put(routeId, getDefaultConfig());
        }  
        return super.isAllowed(routeId, id);
    }
}

限流配置

如下我们分别配置基于IP,基于路径,基于用户名的限流处理

@Component
public class RequestRateLimiterConfig {

    /**
     * ip地址限流
     *
     * @return 限流key
     */
    @Bean
    @Primary
    public KeyResolver remoteAddressKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
    }

    /**
     * 请求路径限流
     *
     * @return 限流key
     */
    @Bean
    public KeyResolver apiKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getPath().value());
    }

    /**
     * username限流
     *
     * @return 限流key
     */
    @Bean
    public KeyResolver userKeyResolver() {
        return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("username"));
    }
}

工作原理及核心内容

基于gateway开发网关,基于springcloud的微服务电商项目

至此,我们基本对spring cloud 的gateway有了个初步的认识。