全局过滤器 (GlobalFilter)
SpringCloud Gateway 支持自定义过滤器,可以很灵活的进行请求或者响应的控制。
自定义过滤器的方法是实现 GlobalFilter 接口、实现 Ordered 接口。这两个接口的全路径为:
- org.springframework.cloud.gateway.filter.GlobalFilter
- org.springframework.core.Ordered
获取请求参数
通关拦截请求参数我们可以作鉴权、限流等
通过实现 GlobalFilter 和 Ordered 这两个接口中的 filter(进行全局过滤)和 getOrder(指定过滤器的优先级)方法
其中,FilterChain 维护了一个链表,链表中存放着配置对象的链条,每次用户调用 一次 chain.doFilter(request, response),链表就去取下一个配置对象,再通过配置对象 得到下一个 filter,然后调用该 filter,接着在 filter 里写的逻辑就被执行了。
@Slf4j
@Order(Ordered.HIGHEST_PRECEDENCE)
@Component
public class AuthorizeFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取请求头
HttpHeaders headers = exchange.getRequest().getHeaders();
// 获取请求参数
MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
// 获取用户名称
String username = params.getFirst("username");
// 请求路径
String requestPath = String.valueOf(exchange.getRequest().getPath());
log.info("网关路由路径:{}",requestPath);
// 校验
if ("admin".equals(username)) {
// 放行
return chain.filter(exchange);
}
//禁止访问,设置状态码
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
// 结束处理
return exchange.getResponse().setComplete();
}
}
获取响应报文
通关拦截响应报文我们可以修改响应报文 例如身份证号,手机号码脱敏等
@Component
@Slf4j
public class ResponseGlobalFilter implements GlobalFilter, Ordered {
@Resource
private RedisTemplate<String,Integer> redisTemplate;
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取响应
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
// 获取请求参数
MultiValueMap<String, String> params = exchange.getRequest().getQueryParams();
// 获取用户名称
String username = params.getFirst("username");
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
if (body instanceof Flux) {
Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body;
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {//解决返回体分段传输
StringBuffer stringBuffer = new StringBuffer();
dataBuffers.forEach(dataBuffer -> {
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
DataBufferUtils.release(dataBuffer);
try {
stringBuffer.append(new String(content, "utf-8"));
} catch (Exception e) {
e.printStackTrace();
}
});
String result = stringBuffer.toString();
log.info("响应报文:{}",result);
//这里可以修改返回内容,返回内容是JSON字符串
byte[] uppedContent = new String(result.getBytes(), Charset.forName("UTF-8")).getBytes();
originalResponse.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}));
}
return super.writeWith(body);
}
};
return chain.filter(exchange.mutate().response(decoratedResponse).build());
}
@Override
public int getOrder() {
return -2;
}
}