遇到这么一个面试题:自定义网关过滤器实现把url中的请求参数放到http的header中传递给微服务。
我们知道网关的一个重要的作用就是路由转发,路由表的配置大概是这个样子:
yml
spring:
cloud:
gateway:
routes:
- id: user-service
uri: http://localhost:8081
predicates:
- Path=/user/*
filters:
- QueryToHeader=authorization,auth
其中的filters就是配置的路由过滤器,Spring已经内置了31个路由的过滤器,这些过滤器都是org.springframework.cloud.gateway.filter.GatewayFilter
的子类,每一种过滤器都是由一种实现了org.springframework.cloud.gateway.filter.factory.GatewayFilterFactory
接口的过滤器工厂来生成的,比如:
AddRequestHeaderGatewayFilterFactory
生成AddRequestHeader
的过滤器AddRequestParameterGatewayFilterFactory
生成AddRequestParameter
的过滤器StripPrefixGatewayFilterFactory
生成StripPrefix
的过滤器.
我们现在就需要自定义一个这样的路由过滤器,实现把url中的请求参数放到http的header中传递给微服务,比如:
yml
filters:
- QueryToHeader=authorization,auth
首先,我们要写一个GatewayFilterFactory的实现类,这里我们选择继承AbstractGatewayFilterFactory:
java
@Component
public class QueryToHeaderGatewayFilterFactory extends
AbstractGatewayFilterFactory<QueryToHeaderGatewayFilterFactory.QueryToHeaderConfig> {
public QueryToHeaderGatewayFilterFactory() {
super(QueryToHeaderConfig.class);
}
/**定义路由过滤器的参数的顺序*/
@Override
public List<String> shortcutFieldOrder() {
return Arrays.asList("queryName", "headerName");
}
@Override
public GatewayFilter apply(final QueryToHeaderConfig config) {
return new GatewayFilter() {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
// 根据请求参数的名字,获取参数的值
String queryValue = request.getQueryParams().getFirst(config.getQueryName());
// 如果没有值,直接放行
if(!StringUtils.hasLength(queryValue)){
return chain.filter(exchange);
}
// 把参数重新放到header中,header的key是在配置中配置好的
request.mutate().header(config.getHeaderName(), queryValue);
return chain.filter(exchange);
}
};
}
/**封装路由过滤器的参数*/
@Validated
public static class QueryToHeaderConfig {
protected @NotEmpty String queryName;
protected @NotEmpty String headerName;
public QueryToHeaderConfig() {
}
public String getQueryName() {
return this.queryName;
}
public QueryToHeaderConfig setQueryName(String queryName) {
this.queryName = queryName;
return this;
}
public String getHeaderName() {
return this.headerName;
}
public QueryToHeaderConfig setHeaderName(String headerName) {
this.headerName = headerName;
return this;
}
@Override
public String toString() {
return (new ToStringCreator(this)).append("headerName", this.headerName).append("queryName", this.queryName).toString();
}
}
}
打开浏览器,测试一下,比如输入:http://localhost:8080/user/2?authorization=456
微服务中可以从header中读取到auth的值是456。
源码下载:https://github.com/xjs1919/enumdemo/tree/master/gateway-filter-demo