前言
loveqq-framework 作为网关框架使用时,修改响应体是一个十分常见的需求。
而作为一个使用过 spring gateway 的作者,我觉得 spring gateway 中修改响应体实在是复杂,因此 loveqq 框架在实现修改响应体时,则力求简洁易用。
如何实现?
loveqq 框架修改响应体是基于网关过滤器(GatewayFilter)实现的,因此要实现修改响应体只需两步:
1、自定义网关过滤器
2、给指定的路由配置这个过滤器
下面给出相应的示例:
网关过滤器:
java
/**
* 这里手动设置 bean name 为:FormatResponseBody
* 后面配置时会用到,当然自动生成的也可以,只是名称比较长而已
* <p>
* 注意:这里设置过滤器优先级为最低级别,因为需要转发请求之后才能获取下游响应体,而转发过滤器默认的级别比较低
*/
@Order(Integer.MAX_VALUE)
@Component("FormatResponseBody")
public static class FormatResponseBodyGatewayFilter implements GatewayFilter {
@Override
public Mono<Void> doFilter(ServerRequest request, ServerResponse response, GatewayFilterChain chain) {
return chain.doFilter(request, response)
.then(Mono.defer(response::getAggregateBody)) // 可以直接获取聚合后的响应体,避免 Flux 分段处理数据
.map(e -> {
byte[] bytes = NIOUtil.read(e);
JSON json = new JSON();
json.put("data", new String(bytes));
json.put("code", 0);
return NIOUtil.from(json.toString()); // 修改响应体
})
.flatMap(json -> response.writeBody(Flux.just(json))) // 响应体写入响应
.then();
}
}
应用过滤器:
yaml
k:
server:
gateway:
routes:
- uri: lb://demo
predicates: Path=/api/demo/**
filters:
- id: StripPrefix # 去除 /api
args:
stripPrefix: 1
- id: FormatResponseBody # 修改响应体
这样就可以了。
响应体校验不通过想抛出异常?
很简单,直接抛出异常就可以了,例如:
java
@Override
public Mono<Void> doFilter(ServerRequest request, ServerResponse response, GatewayFilterChain chain) {
return chain.doFilter(request, response)
.then(Mono.defer(response::getAggregateBody)) // 可以直接获取聚合后的响应体,避免 Flux 分段处理数据
.map(e -> {
String body = new String(NIOUtil.read(e));
if (body.charAt(0) != '{' || body.charAt(0) != '[') {
throw new ResolvableException("not json");
}
JSON json = new JSON();
json.put("data", body);
json.put("code", 0);
return NIOUtil.from(json.toString()); // 修改响应体
})
.flatMap(json -> response.writeBody(Flux.just(json))) // 响应体写入响应
.then();
}
这样的话,网关会输出正常的错误信息吗?
当然可以,因为网关异常同样可以走 mvc 模式的全局异常处理器进行处理!
java
@RestControllerAdvice(supportAny = true)
public class GlobalExceptionHandler {
/**
* 异常处理
*
* @param request 抽象的统一的请求对象
* @param e 异常
* @return 返回错误信息
*/
@ExceptionHandler
public String onException(ServerRequest request, Exception e) {
return e.getClass().getName() + ":" + e.getMessage();
}
}
看起来相当简洁,几乎和修改请求体没什么区别,但是 spring gateway 修改请求体 / 响应体想必做过的各位懂的都懂。
感兴趣的同学可以尝试一下~