Spring Cloud Gateway入门学习

15 篇文章 0 订阅
7 篇文章 1 订阅

Spring Cloud Gateway入门学习


Spring Cloud Gateway是Spring Cloud的一个项目,它是基于Spring,Webflux,Spring boot等技术开发的网关,它旨在为微服务架构提供一种简单有效的统一的API路由管理方式,目标为替换Netflix Zuul项目,其不仅提供统一的路由方式,并且基于Filter链的方式提供了网关基本的功能,例如:安全,监控/指标和限流。

Spring Cloud Gateway的主要特征:

  • 基于Spring Framework 5,SpringBoot2.0
  • 动态路由
  • Predicates和Filters作用于特定路由
  • 集成Hystrix断路器
  • 集成SpringCloud DiscoveryClient
  • 易于编写的Predicates和Filters
  • 限流
  • 路径重写

基本概念:

Route(路由):这是网关的基本构建块。它由一个ID,一个目标uri,一组断言和一组过滤器定义。如果断言成功,则路由匹配。

Predicate(断言):这是一个java8的Predicate。输入类型是一个ServerWebExchange。我们可以使用它来匹配来自HTTP请求的任何内容,例如headers或参数。

Filter(过滤器):我们可以使用 它来修改请求和参数。

一,基本使用

1.1 引用依赖

springboot版本2.4.5,springcloud版本2020.0

		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
            <version>3.0.2</version> 
        </dependency>
		<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
            <version>3.0.1</version>
        </dependency>

1.2 启动类

package com.lmc.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * @author lmc
 * @Description: TODO
 * @Create 2021-10-13 23:08
 * @version: 1.0
 */
@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication5010 {

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

}

1.3 配置文件

server:
  port: 5010

spring:
  application:
    name: tools-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true # #开启根据注册中心路由,并随服务的改变而改变路由
          lower-case-service-id: true # #开启服务名转为小写
      routes:
        - id: tools-task
          uri: lb://tools-task
          predicates:
            - Path=/tltk
      filters:
        - StripPrefix=1

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/
  instance:
    prefer-ip-address: true

spring.cloud.gateway.routes.id:自定义的路由ID,保持唯一

spring.cloud.gateway.routes.id.uri:目标服务地址

spring.cloud.gateway.routes.id.uri: lb//XXXX(服务名):配置服务

spring.cloud.gateway.routes.id.predicates:路由条件,predicates接受一个输入参数,返回一个布尔值结果。该接口包含多种默认方式来将predicate组合成其他复杂的逻辑

spring.cloud.gateway.routes.id.filters StripPrefix=n:去掉n个路径

spring.cloud.gateway.discovery.locator.enabled:是否根据注册中心路由,随服务的改变而改变路由

spring.cloud.gateway.discovery.locator.lower-case-service-id:是否强制将服务名转为小写

1.4 测试

现服务tools-task接口: http://localhost:8083/test/api

先启动服务注册中心,再启动gateway,再启动tools-task,访问: http://localhost:5010/tools-task/test/api,成功访问数据

二, 过滤器

​ 在Spring Cloud Gateway中,过滤器的作用主要是为对请求与返回进行处理,可以简单理解为一个方法的前置事件与后置事件,所以一般过滤器被分为两种,分别为“pre”和“post”。在“pre”类型的过滤器可以做参数校验,权限校验,流量监控,日志输出,协议转换等,在“post”类型的过滤器中可以做响应内容,响应头的修改,日志输出,流量监控等。

过滤器执行过程中,order越大,优先级越低

2.1 常用过滤器

  • AddRequestHeader:为请求增加一个header
  • AddRequestParameter:为请求新增请求参数
  • AddResponseHeader:为响应新增返回header
  • DedupeResponseHeader:为去除返回信息中重复的header信息
  • ……

2.2 自定义过滤器

自定义过滤器,需要实现GatewayFilter和Ordered接口

举例: 请求完成时间过滤器

package com.lmc.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

/**
 * 计算请求完成时间过滤器
 * @author sw
 *
 */
public class ElapsedFilter implements GatewayFilter, Ordered {
	
	/**
	 * 过滤器存在优先级,order越大,优先级越低
	 */
	@Override
	public int getOrder() {
		// TODO Auto-generated method stub
		return Ordered.LOWEST_PRECEDENCE;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		exchange.getAttributes().put("beginTime", System.currentTimeMillis());
		return chain.filter(exchange).then(
					Mono.fromRunnable(() -> {
						Long startTime = exchange.getAttribute("beginTime");
						if (startTime != null) {
							System.out.println(exchange.getRequest().getURI().getRawPath() + " : " + (System.currentTimeMillis() - startTime) + "ms");
						}
					})
				);
	}
}

然后将该过滤器绑定到路由中:

	@Bean
	public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
		return builder.routes()
				.route(r -> r.path("/lmchh/**")
						.filters(f -> f.stripPrefix(1)
								.filter(new ElapsedFilter()))
						.uri("http://localhost:5020")
						.order(0))
				.build();
	}

2.3 全局过滤器

当需要所有请求都要经过某些操作时,可以使用全局过滤器。全局过滤器需要实现GlobalFilter接口

package com.lmc.filter;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

/**
 * 全局过滤器
 * 所有请求都会执行
 * @author sw
 *
 */
@Component
public class GlobalFilter implements org.springframework.cloud.gateway.filter.GlobalFilter, Ordered {

	@Override
	public int getOrder() {
		// TODO Auto-generated method stub
		return -10;
	}

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		System.out.println("this is global filter ... start ...");
		return chain.filter(exchange).then(
				Mono.fromRunnable(() -> {
					System.out.println("this is global filter ... end ...");
				})
			);
	}
}

三, Gateway功能

3.1 认证

举例,认证过滤器:

package com.lmc.filter;

import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;

/**
 * 对客户端header中的Authorization信息进行简单认证
 * @author sw
 *
 */
@Component
public class TokenAuthenticationFilter extends AbstractGatewayFilterFactory {
	
	private static final String Bearer_ = "Bearer ";

	@Override
	public GatewayFilter apply(Object config) {
		// TODO Auto-generated method stub
		return (exchange, chain) -> {
			ServerHttpRequest request = exchange.getRequest();
			ServerHttpRequest.Builder mutate = request.mutate();
			ServerHttpResponse response = exchange.getResponse();
			try {
				//获取header中的Authorization
				String header = request.getHeaders().getFirst("Authorization");
				if (header == null || !header.startsWith(Bearer_)) {
					throw new RuntimeException("请求头中Authorization的信息为空");
				}
				//截取Authorization Bearer
				String token = header.substring(7);
				//可把token存到redis中,此时直接在redis中判断是否由此key,有则校验通过,否则校验失败
				if(!StringUtils.isEmpty(token)) {
					System.out.println("校验通过");
					//有token,把token设置到header中,传递给后端服务
					mutate.header("userDetails", token).build();
				}else {
					//token无效
					System.out.println("token无效");
					return null;
				}
				
			} catch (Exception e) {
				// TODO: handle exception
				e.printStackTrace();
			}
			ServerHttpRequest build = mutate.build();
			return chain.filter((ServerWebExchange) exchange.mutate().request(build));
		};
	}
}

配置:

		filters:
          - StripPrefix=1
          # 进行token认证
          - TokenAuthenticationFilter

3.2 熔断

熔断降级:在分布式系统中,网关作为流量的入口,大量请求进入网关,向后端远程系统或服务发起调用,后端服务不可避免的会产生调用失败(超时或者异常),失败时不能让请求堆积在网关上,需要快速失败并返回回去,这就需要在网关上做熔断,降级操作。

所需依赖:

<!-- 熔断,降级 -->
  	<dependency>
  		<groupId>org.springframework.cloud</groupId>
  		<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
  	</dependency>

配置:

		filters:
          - StripPrefix=1
          ## 熔断降级配置
          - name: Hystrix
            args:
              name: defaultfallback
              fallbackUri: 'forward:/defaultfallback'

举例,熔断回调:

package com.lmc.controller;

import java.util.HashMap;
import java.util.Map;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;

@RestController
public class DefaultHystrixController {

	@RequestMapping("/defaultfallback")
	@HystrixCommand(commandProperties= {
				@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value = "3000")
			})
	public Map<String, Object> defaultfallback() {
		System.out.println("默认降级操作...");
		Map<String, Object> map = new HashMap<String, Object>();
		map.put("resultCode", "fail");
		map.put("resultMessage", "服务异常...");
		map.put("returnObj", null);
		return map;
	}
}

创建接口测试:

设置3秒内没响应就进行熔断降级

	@RequestMapping("/timeout")
	public String timeout() {
		try {
			Thread.sleep(5000);
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
		return "timeout";
	}	

设置/timeout映射睡眠5秒,引发熔断机制。

访问 /timeout ,结果调用了/defaultfallback。

3.3 限流

限流:网关上有大量请求,对指定服务进行限流,可以很大程度上提高服务的可用性与稳定性,限流的目的是通过对并发访问/请求进行限速,或对一个时间窗口内的请求进行限速来保护系统。一旦达到限制速率则可以拒绝服务,排队或等待,降级。

集成限流:Spring Cloud Gateway默认集成了Redis限流,可以对不同服务做不同维度的限流,如:IP限流,用户限流,接口限流。(需提前开启Redis)

举例,新建限流配置类,通过KeyResolver来指定限流的key

package com.lmc.config;

import org.springframework.cloud.gateway.filter.ratelimit.KeyResolver;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import reactor.core.publisher.Mono;
/**
 * 路由限流配置
 * @author sw
 *
 */
@Configuration
public class RateLimiterConfig {

	@Bean(value = "remoteAddrKeyResolver")
	public KeyResolver remoteAddrKeyResolver() {
		//IP限流
		return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getAddress().getHostAddress());
		//接口限流  
		// return exchange -> Mono.just(exchange.getRequest().getPath().value());
	}
}

限流方式:

  • IP限流
  • 接口限流
  • 用户限流

配置类

spring:
  application:
    name: api-gateway
  cloud:
    gateway:
      discovery:
        locator:
          enabled: true #开启根据注册中心路由,并随服务的改变而改变路由
          lower-case-service-id: true #开启服务名转为小写
      routes:
        - id: provider
          uri: lb://api-eureka-provider
          predicates:
            - Path=/provider/**
          filters:
          	- StripPrefix=1
            # 进行token认证
            #- TokenAuthenticationFilter
            ## 熔断降级配置
            - name: Hystrix
              args:
                name: defaultfallback
                  fallbackUri: 'forward:/defaultfallback'
            - name: RequestRateLimiter
              args:
                # 使用SpEL名称引用Bean,与上面新建的RateLimiterConfig类中的bean的name相同
                key-resolver: '#{@remoteAddrKeyResolver}'
                # 每秒最大访问次数
                redis-rate-limiter.replenishRate: 2
                # 令牌桶最大容量
                redis-rate-limiter.burstCapacity: 2

注意:

filter名称必须是RequestRateLimiter,

redis-rate-limiter.replenishRate:允许用户每秒处理多少个请求

redis-rete-limiter.burstCapacity:令牌桶的容量,允许在一秒内完成的最大请求数。

key-resolver:使用SpEL按名称引用bean

3.4 动态路由

动态路由的内容较多,今天做笔记已经做到十一点半,下篇再讲好了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值