SpringCloud_Gateway

依赖pom.xml

<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>
	<parent>
		<groupId>org.pingruan</groupId>
		<artifactId>vander-framework-parent</artifactId>
		<version>0.0.1-SNAPSHOT</version>
	</parent>
	<groupId>org.pingruan.springboot</groupId>
	<artifactId>vander-gateway-center</artifactId>

	<dependencies>
		<!-- 服务监控 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<!-- 远程服务调用熔断 -->
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
		</dependency>
		<!-- 重试功能 -->
		<dependency>
			<groupId>org.springframework.retry</groupId>
			<artifactId>spring-retry</artifactId>
		</dependency>
		<!-- 请求限流过滤器 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-redis-reactive</artifactId>
		</dependency>
		<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.cloud</groupId>
			<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
		</dependency>
	</dependencies>
</project>

配置文件bootstrap.yml

server:
  port: 9004
spring:
  application:
    name: vander-gateway-center
    
#------------网关配置------------------    
  cloud: 
    gateway:
      routes:
      - id: client1  # 1、ID唯一
        uri: lb://vander-client-demo   # 2、lb(注册中心名称)和ws(webservice路径)
        predicates:   # 3、规则路径匹配
        - Path=/client1/**
        filters: 
        - StripPrefix=1  # 截取1个路径   
        - name: Retry   # 重试配置(无需配置熔断)
          args:
            retries: 3 #重试次数,不包含本次(4次) 
            status: 404
            statusSeries: 500
            method: GET        
      - id: client2  # 1、ID唯一
        uri: lb://vander-client-demo-a   # 2、lb(注册中心名称)和ws(webservice路径)
        predicates:   # 3、规则路径匹配
        - Path=/client2/**
        filters:      # 4、拦截器组合
        - StripPrefix=1
        - name: Hystrix  # 远程调用熔断配置(重试配置无效)
          args: 
            name: authHystrixCommand
            fallbackUri: forward:/hystrixTimeout
        - name: Jwt  #   自定义限流配置jwt
          args:
            keyResolver: apiKeyResolver
            redis-rate-limiter.replenishRate: 10  # 用户每秒处理多少个请求
            redis-rate-limiter.burstCapacity: 20  # 用户允许在一秒钟内完成的最大请求数


#------------注册中心配置------------------
eureka:
  client:
    registerWithEureka: true #服务注册开关
    fetchRegistry: true #服务发现开关
    serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址,多个中间用逗号分隔
      defaultZone: ${EUREKA_SERVERS:http://root:qwe123@server1:9001/eureka/}
  instance:
    prefer-ip-address: true  #将自己的ip地址注册到Eureka服务中
    ip-address: ${IP_ADDRESS:127.0.0.1}
    instance-id: ${spring.application.name}:${server.port} #指定实例id

配置源码

/**
 * 解决跨域
 * 
 * @author vander
 *
 */
public class CorsConfiguration {
	// 这里为支持的请求头,如果有自定义的header字段请自己添加(不知道为什么不能使用*)
	private static final String ALLOWED_HEADERS = "*";
	private static final String ALLOWED_METHODS = "*";
	private static final String ALLOWED_ORIGIN = "*";
	private static final String ALLOWED_Expose = "*";
	private static final String MAX_AGE = "18000L";

	@Bean
	public WebFilter corsFilter() {
		return (ServerWebExchange ctx, WebFilterChain chain) -> {
			ServerHttpRequest request = ctx.getRequest();
			if (CorsUtils.isCorsRequest(request)) {
				ServerHttpResponse response = ctx.getResponse();
				HttpHeaders headers = response.getHeaders();
				headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN);
				headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
				headers.add("Access-Control-Max-Age", MAX_AGE);
				headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
				headers.add("Access-Control-Expose-Headers", ALLOWED_Expose);
				headers.add("Access-Control-Allow-Credentials", "true");
				if (request.getMethod() == HttpMethod.OPTIONS) {
					response.setStatusCode(HttpStatus.OK);
					return Mono.empty();
				}
			}
			return chain.filter(ctx);
		};
	}

	/**
	 *
	 * 如果使用了注册中心(如:Eureka),进行控制则需要增加如下配置
	 */
	@Bean
	public RouteDefinitionLocator discoveryClientRouteDefinitionLocator(DiscoveryClient discoveryClient) {
		return new DiscoveryClientRouteDefinitionLocator(discoveryClient, null);
	}
}

/**
 * 配置限流key配置
 * 
 * @author vander
 *
 */
@Configuration
@Slf4j
public class GatewayConfiguration {
	
	/**
	 * 接口限流操作
	 * 
	 * @return
	 */
	@Bean(name = "apiKeyResolver")
	public KeyResolver apiKeyResolver() {
		// 根据api接口来限流
		log.info("接口限流操作...");
		return exchange -> Mono.just(exchange.getRequest().getPath().value());

	}

	/**
	 * ip限流操作
	 * 
	 * @return
	 */
	@Bean(name = "ipKeyResolver")
	public KeyResolver ipKeyResolver() {
		return exchange -> Mono.just(exchange.getRequest().getRemoteAddress().getHostName());
	}

	/**
	 * 用户限流 使用这种方式限流,请求路径中必须携带userId参数。
	 * 
	 * @return
	 */
	@Bean(name = "userKeyResolver")
	KeyResolver userKeyResolver() {
		return exchange -> Mono.just(exchange.getRequest().getQueryParams().getFirst("userId"));
	}

}

/**
 * 全局过滤器配置
 * 
 * @author vander
 *
 */
@Configuration
@Slf4j
public class GlobalRouteFilter implements GlobalFilter{

	@Override
	public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
		ServerHttpRequest.Builder builder = exchange.getRequest().mutate();
		ServerHttpRequest serverHttpRequest = builder.build();
		String token = serverHttpRequest.getHeaders().getFirst("token");//校验token
		log.info("GlobalRouteFilter..."+token);
        builder.header("GlobalFilter","GlobalFilter success");
        chain.filter(exchange.mutate().request(builder.build()).build());
        return chain.filter(exchange.mutate().request(builder.build()).build());
	}

}

/**
 * 
 * 局部过滤器配置
 * 
 * 请求验证
 * 1、创建过滤器,命名规则:  jwt + GatewayFilterFactory
 * 2、配置文件中配置限流 jwt
 * 
 * 
 * @author vander
 *
 */
@Component
@Slf4j
public class JwtGatewayFilterFactory extends AbstractGatewayFilterFactory<Object> {
	public GatewayFilter apply() {
        return apply(o -> {
        });
    }
	@Override
	public GatewayFilter apply(Object config) {
		return (exchange,chain)->{
			ServerHttpRequest serverHttpRequest = exchange.getRequest();
			/**
			 * 获取请求信息,进行验证
			 */
			String token = serverHttpRequest.getHeaders().getFirst("token");//获取header中token进行校验
			log.info("请求校验..."+token);
			return chain.filter(exchange);
		};
	}

}

/**
 * 熔断响应
 * 
 * @author vander
 *
 */
@Slf4j
@RestController
public class HystrixCommandController {

	@RequestMapping("/hystrixTimeout")
	public String hystrixTimeout() {
		log.info("hystrixTimeout...");
		return "ok";
	}
	
	@HystrixCommand(commandKey="authHystrixCommand")
	public void authHystrixCommand() {
		log.info("触发hystrixTimeout...");
	}
}

/**
 * 
 * 
 * @author vander
 *
 */
@EnableDiscoveryClient
@SpringBootApplication
@ComponentScan(basePackages= {"org.pingruan.gateway"})
public class SpringBootGateway {

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

猜你喜欢

转载自blog.csdn.net/qq_15764943/article/details/87704760