server:
port: 7013
---
spring:
cloud:
gateway:
routes:
- id: add_request_header_route
uri: http://httpbin.org
filters:
- AddRequestHeader=X-Request-Flag, HelloWorld
predicates:
- After=2019-06-20T00:00:00+08:00[Asia/Shanghai]
profiles: add_request_header_route
AddRequestHeaderGatewayFilterFactory的源码
package org.springframework.cloud.gateway.filter.factory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.http.server.reactive.ServerHttpRequest;
/**
* @author Spencer Gibb
*/
public class AddRequestHeaderGatewayFilterFactory
extends AbstractNameValueGatewayFilterFactory {
@Override
public GatewayFilter apply(NameValueConfig config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest().mutate()
.header(config.getName(), config.getValue()).build();
return chain.filter(exchange.mutate().request(request).build());
};
}
}
从代码可知道,由当前的ServerHttpRequest创建新 ServerHttpRequest ,并在新的ServerHttpRequest加一个请求头,然后创建新的 ServerWebExchange ,提交过滤器链继续过滤。
---
spring:
cloud:
gateway:
routes:
- id: add_response_header_route
uri: http://httpbin.org:80/get
filters:
- AddResponseHeader=X-Response-Flag, Hadron
predicates:
- After=2019-06-20T00:00:00+08:00[Asia/Shanghai]
profiles: add_response_header_route
C:\Windows\System32>curl -I localhost:7013
HTTP/1.1 200 OK
X-Response-Flag: Hadron
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Content-Type: text/html; charset=utf-8
Date: Fri, 21 Jun 2019 09:01:14 GMT
Referrer-Policy: no-referrer-when-downgrade
Server: nginx
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block
Content-Length: 0
---
spring:
cloud:
gateway:
routes:
- id: rewritepath_route
uri: https://blog.csdn.net/chengyuqiang
predicates:
- Path=/foo/**
filters:
- RewritePath=/foo/(?<segment>.*), /$\{segment}
profiles: rewritepath_route
RewritePath 过滤器将/foo/(?.*)重写为{segment},然后转发到https://blog.csdn.net。
比如请求http://localhost:7013/foo/chengyuqiang
,RewritePath 过滤器将/foo/chengyuqiang
重写为chengyuqiang
,然后转发到https://blog.csdn.net
,这样路径就是https://blog.csdn.net/chengyuqiang
http://localhost:7013/foo/chengyuqiang
---
spring:
cloud:
gateway:
routes:
- id: prefixpath_route
uri: https://blog.csdn.net
predicates:
- Path=/article/**
filters:
- PrefixPath=/chengyuqiang
profiles: prefixpath_route
比如:请求/hello,最后转发到目标服务的路径变为/chengyuqiang/hello
http://localhost:7013/article/details/85019277
注意,这个页面会再次跳转到https://www.csdn.net/首页
---
spring:
cloud:
gateway:
routes:
- id: stripprefix_route
uri: https://httpbin.org
predicates:
- Path=/my/**
filters:
- StripPrefix=2
profiles: stripprefix_route
比如,请求/my/bar/get,( StripPrefix=2)去除掉前面两个前缀之后,最后转发到目标服务的路径为/get
http://localhost:7013/my/bar/get
下面,我们自定义一个filter用来统计每次请求的时长。
package com.cntaiping.tpa.gatewayfilter.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;
public class MyFilter implements GatewayFilter, Ordered {
private static final String REQUEST_TIME_BEGIN = "requestTimeBegin";
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//记录请求开始时间,并保存在ServerWebExchange中
exchange.getAttributes().put(REQUEST_TIME_BEGIN, System.currentTimeMillis());
return chain.filter(exchange)//“pre”类型的过滤器
.then(Mono.fromRunnable(// run()方法中相当于"post"过滤器
() ->{
Long startTime = exchange.getAttribute(REQUEST_TIME_BEGIN);
if (startTime != null) {
System.out.println(exchange.getRequest().getURI() + " 耗时" + (System.currentTimeMillis() - startTime));
}
}
));
}
@Override
public int getOrder() {
//设定优先级别的,值越大则优先级越低
return 0;
}
}
将自定义filter注册到路由中
package com.cntaiping.tpa.gatewayfilter;
import com.cntaiping.tpa.gatewayfilter.filter.MyFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.filter.factory.AddRequestHeaderGatewayFilterFactory;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayFilterApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayFilterApplication.class, args);
}
@Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/my/**")
.filters(f -> f.filter(new MyFilter())
.addResponseHeader("X-Response-Default-Flag", "Default-Flag"))
.uri("http://httpbin.org:80/get")
.order(0)
.id("my_filter_router")
)
.build();
}
}
重启服务
curl localhost:7013/my/123
下面演示自定义过滤器工厂类,这样就可以非常方便的在配置文件中配置过滤器。
springboot约定过滤器工厂的前缀为配置的name,所以自定义的过滤器工厂类的后缀是GatewayFilterFactory
package com.cntaiping.tpa.gatewayfilter.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import reactor.core.publisher.Mono;
import java.util.*;
public class MyGatewayFilterFactory extends AbstractGatewayFilterFactory<MyGatewayFilterFactory.Config> {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 定义可以再yaml中声明的属性变量
*/
private static final String TYPE = "type";
private static final String OP = "op";
public MyGatewayFilterFactory(){
// 这里需要将自定义的config传过去,否则会报告ClassCastException
super(Config.class);
}
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList(TYPE, OP);
}
@Override
public GatewayFilter apply(Config config) {
return ((exchange, chain) -> {
boolean root = "root".equals(config.getOp());
if (root){
logger.info("GatewayFilter root");
}
else {
logger.info("GatewayFilter customer");
}
// 在then方法里的,相当于aop中的后置通知
return chain.filter(exchange).then(Mono.fromRunnable(()->{
// do something
logger.info(System.currentTimeMillis()+"");
}));
});
}
/**
* 自定义的config类,用来设置传入的参数
*/
public static class Config {
/**
* 过滤类型
*/
private String type;
/**
* 操作
*/
private String op;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getOp() {
return op;
}
public void setOp(String op) {
this.op = op;
}
}
}
package com.cntaiping.tpa.gatewayfilter;
import com.cntaiping.tpa.gatewayfilter.filter.MyFilter;
import com.cntaiping.tpa.gatewayfilter.filter.MyGatewayFilterFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayFilterApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayFilterApplication.class, args);
}
/* @Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/my/**")
.filters(f -> f.filter(new MyFilter())
.addResponseHeader("X-Response-Default-Flag", "Default-Flag"))
.uri("http://httpbin.org:80/get")
.order(0)
.id("my_filter_router")
)
.build();
}*/
@Bean
public MyGatewayFilterFactory exampleGatewayFilterFactory(){
return new MyGatewayFilterFactory();
}
}
---
spring:
cloud:
gateway:
routes:
- id: myfilter_route
uri: http://httpbin.org:80/get
filters:
- name: My
args:
op: root
type: he
predicates:
- After=2017-01-20T17:42:47.789-07:00[America/Denver]
profiles: myfilter_route
package com.cntaiping.tpa.gatewayfilter.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
public class TokenFilter implements GlobalFilter, Ordered {
private Logger logger = LoggerFactory.getLogger(getClass());
/**
* 该全局过滤器会校验请求中是否包含token请求参数
* 如何不包含,则不转发路由;否则执行正常的逻辑。
* @param exchange
* @param chain
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = exchange.getRequest().getQueryParams().getFirst("token");
if (token == null || token.isEmpty()) {
logger.info( "token is empty..." );
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -100;
}
}
package com.cntaiping.tpa.gatewayfilter;
import com.cntaiping.tpa.gatewayfilter.filter.MyFilter;
import com.cntaiping.tpa.gatewayfilter.filter.MyGatewayFilterFactory;
import com.cntaiping.tpa.gatewayfilter.filter.TokenFilter;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.gateway.route.RouteLocator;
import org.springframework.cloud.gateway.route.builder.RouteLocatorBuilder;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class GatewayFilterApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayFilterApplication.class, args);
}
/* @Bean
public RouteLocator customerRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(r -> r.path("/my/**")
.filters(f -> f.filter(new MyFilter())
.addResponseHeader("X-Response-Default-Flag", "Default-Flag"))
.uri("http://httpbin.org:80/get")
.order(0)
.id("my_filter_router")
)
.build();
}*/
@Bean
public MyGatewayFilterFactory exampleGatewayFilterFactory(){
return new MyGatewayFilterFactory();
}
@Bean
public TokenFilter tokenFilter(){
return new TokenFilter();
}
}