创建一个单独的网关服务
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-gatewayartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
@SpringBootApplication
@EnableDiscoveryClient
public class GateWayApplication {
public static void main(String[] args) {
SpringApplication.run(GateWayApplication.class,args);
}
}
server:
port: 9999
spring:
application:
name: gateway
eureka:
client:
service-url:
# eureka 服务地址,如果是集群的话;需要指定其它集群eureka地址
defaultZone: http://127.0.0.1:10086/eureka
# 是否注册到服务端
register-with-eureka: true
# 是否拉取服务列表
fetch-registry: true
instance:
ip-address: 127.0.0.1 # 服务的ip地址
prefer-ip-address: true # 启用ip地址访问
server:
port: 9999
spring:
application:
name: gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址
uri: http://127.0.0.1:8082
# 路由断言,可以配置映射路径
predicates:
- Path=/user/**
服务提供方的访问地址如下:
http://localhost:8082/user/findList?id=2
http://localhost:9999/user/findList?id=2
server:
port: 9999
spring:
application:
name: gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址
uri: lb://user-server
# 路由断言,可以配置映射路径
predicates:
- Path=/user/**
user-server为要访问的服务名
参考:官方文档
假设要访问的服务请求路径为:
http://localhost:8082/api/user/findList?id=2
网关配置如下:
server:
port: 9999
spring:
application:
name: gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址
uri: lb://user-server
# 路由断言,可以配置映射路径
predicates:
- Path=/user/**
filters:
- PrefixPath=/api #为请求增加一个前缀
当测试访问的路径为: http://localhost:9999/user/findList?id=2 的时候可以正确请求到服务。
假设要访问的服务请求路径为:
http://localhost:8082/user/findList?id=2
网关配置如下:
server:
port: 9999
spring:
application:
name: gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址
uri: lb://user-server
# 路由断言,可以配置映射路径
predicates:
- Path=/api/user/**
filters:
- StripPrefix=1 #为请求删除一个前缀 如果为2就是去除2个前缀
当测试访问的路径为: http://localhost:9999/api/user/findList?id=2 的时候可以正确请求到服务。
添加在default-filters配置里面的都是全局生效的过滤器
server:
port: 9999
spring:
application:
name: gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址
uri: lb://user-server
# 路由断言,可以配置映射路径
predicates:
- Path=/api/user/**
filters:
# - PrefixPath=/api #为请求增加一个前缀
- StripPrefix=1 #为请求删除一个前缀 如果为2就是去除2个前缀
default-filters:
- AddResponseHeader=X-Response-Foo, Bar
测试效果:
定义一个类实现GlobalFilter, Ordered接口
@Component
public class TokenFilter implements GlobalFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
System.out.println("-----------------全局过滤器MyGlobalFilter---------------------");
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (StringUtils.isBlank(token)) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
//值越小越先执行
return 0;
}
}
注意记得加上@Component注解
如果要进行放行:
return chain.filter(exchange)
如果需要拦截请求,过滤器直接给出响应
return exchange.getResponse().setComplete();
如果在过滤器中需要获取请求中的相关数据
ServerHttpRequest request = exchange.getRequest();
//获取发起请求方的IP地址
InetSocketAddress remoteAddress = request.getRemoteAddress();
System.out.println("ip:"+remoteAddress.getHostName());
//获取请求URI
request.getURI();
如果在过滤器中需要获取响应
ServerHttpResponse response = exchange.getResponse();
如果需要对请求进行增强,增加一个请求头
request.mutate().header("请求头name","值");
①定义一个类实现AbstractGatewayFilterFactory接口
注意类名后缀必须为 GatewayFilterFactory
注意记得加上@Component注解
@Component
public class MyParamGatewayFilterFactory extends
AbstractGatewayFilterFactory<MyParamGatewayFilterFactory.Config> {
public static final String PARAM_NAME = "param";
public MyParamGatewayFilterFactory() {
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(PARAM_NAME);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
if (request.getQueryParams().containsKey(config.param)) {
request.getQueryParams().get(config.param)
.forEach(value -> System.out.printf("----------局部过滤器-----%s= %s-----",
config.param, value));
}
return chain.filter(exchange);
};
}
public static class Config {
private String param;
public String getParam() {
return param;
}
public void setParam(String param) {
this.param = param;
}
}
}
②配置
因为类名为MyParamGatewayFilterFactory 所以配置的时候属性名为 MyParam
server:
port: 9999
spring:
application:
name: gateway
cloud:
gateway:
routes:
# 路由id,可以随意写
- id: user-service-route
# 代理的服务地址
uri: lb://user-server
# 路由断言,可以配置映射路径
predicates:
- Path=/api/user/**
filters:
- MyParam=name
spring cloud gateway 默认使用redis的RateLimter限流算法来实现。所以我们要使用首先需要引入redis响应式的依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-data-redis-reactiveartifactId>
<version>2.1.3.RELEASEversion>
dependency>
在启动类中定义KeyResolver
KeyResolver用于计算某一个类型的限流的KEY也就是说,可以通过KeyResolver来指定限流的Key。
//定义一个KeyResolver
@Bean
public KeyResolver ipKeyResolver() {
return new KeyResolver() {
@Override
public Mono<String> resolve(ServerWebExchange exchange) {
return Mono.just(exchange.getRequest().getRemoteAddress().getHostString());
}
};
}
添加redis配置和RequestRateLimiter过滤器配置 和redis的ip地址和端口号
spring:
application:
name: sysgateway
cloud:
gateway:
routes:
- id: goods
uri: lb://goods
predicates:
- Path=/goods/**
filters:
- name: RequestRateLimiter #请求数限流 名字不能随便写
args:
key-resolver: "#{@ipKeyResolver}" #引用Spring容器中的ipKeyResolver
redis-rate-limiter.replenishRate: 1 #令牌桶每秒填充平均速率
redis-rate-limiter.burstCapacity: 1 #令牌桶总容量
redis:
host: 192.168.200.128
port: 6379
####负载均衡和熔断
GateWay集成了Ribbon和Hystrix。如果需要配置相关的负载均衡和熔断请参考对应文档
spring:
cloud:
gateway:
globalcors:
corsConfigurations:
'[/**]':
#allowedOrigins: * # 这种写法或者下面的都可以,*表示全部
allowedOrigins:
- "http://docs.spring.io"
allowedMethods:
- GET
上述配置表示:可以允许来自 http://docs.spring.io 的get请求方式获取服务数据。 allowedOrigins 指定允许访问的服务器地址,如:http://localhost:10000 也是可以的。 ‘[/**]’ 表示对所有访问到网关服务器的请求地址 官网具体说明:https://cloud.spring.io/spring-cloud-static/spring-cloud-gateway/2.1.1.RELEASE/multi/mul ti__cors_configuration.html
启动多个Gateway服务,自动注册到Eureka,形成集群。如果是服务内部访问,访问Gateway,自动负载均衡,没 问题。 但是,Gateway更多是外部访问,PC端、移动端等。它们无法通过Eureka进行负载均衡,那么该怎么办? 此时,可以使用其它的服务网关,来对Gateway进行代理。比如:Nginx