依赖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);
}
}