Spring Cloud Gateway 作为微服务的最前沿,可以实现限流、鉴权等等操作,本文将以修改统一格式的返回参数作为讲解
新建GlobalFilter的实现类
Spring 修改前的默认返回参数如下
{
"status": 404,
"error":"",
"message": "NOT FUND",
"path": "/test",
"timestamp": 1565334087971
}
@Slf4j
@Component
public class OpenGatewayFilter implements GlobalFilter, Ordered {
/** 将 List 数据以""分隔进行拼接 **/
private static Joiner joiner = Joiner.on("");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
DataBufferFactory bufferFactory = response.bufferFactory();
ServerHttpResponseDecorator decorator = new ServerHttpResponseDecorator(response) {
@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 -> {
List<String> list = Lists.newArrayList();
// gateway 针对返回参数过长的情况下会分段返回,使用如下方式接受返回参数则可避免
dataBuffers.forEach(dataBuffer -> {
// probably should reuse buffers
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
// 释放掉内存
DataBufferUtils.release(dataBuffer);
list.add(new String(content, StandardCharsets.UTF_8));
});
// 将多次返回的参数拼接起来
String responseData = joiner.join(list);
// 重置返回参数
String result = response(responseData);
byte[] uppedContent =
new String(result.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8).getBytes();
// 修改后的返回参数应该重置长度,否则如果修改后的参数长度超出原始参数长度时会导致客户端接收到的参数丢失一部分
response.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}));
}
return super.writeWith(body);
}
};
return chain.filter(exchange.mutate().response(decorator).build());
}
@Override
public int getOrder() {
// 必须<=-1
return -2;
}
private String response(String result) {
try {
JSONObject json = JSONObject.fromObject(result);
if (json.containsKey("error")) {
json.clear();
json.put("code", json.get("status"));
json.put("msg", json.getString("message"));
json.put("payload","");
json.put("timestamp", System.currentTimeMillis());
result = json.toString();
}
} catch (Exception e) {
log.warn("转换JSON异常:{}", result);
}
return result;
}
}
新建配置类
覆盖默认的配置
@Configuration
@EnableConfigurationProperties({ServerProperties.class, ResourceProperties.class})
public class ErrorHandlerConfiguration {
private final ServerProperties serverProperties;
private final ApplicationContext applicationContext;
private final ResourceProperties resourceProperties;
private final List<ViewResolver> viewResolvers;
private final ServerCodecConfigurer serverCodecConfigurer;
public ErrorHandlerConfiguration(ServerProperties serverProperties, ResourceProperties resourceProperties,
ObjectProvider<List<ViewResolver>> viewResolversProvider, ServerCodecConfigurer serverCodecConfigurer,
ApplicationContext applicationContext) {
this.serverProperties = serverProperties;
this.applicationContext = applicationContext;
this.resourceProperties = resourceProperties;
this.viewResolvers = viewResolversProvider.getIfAvailable(Collections::emptyList);
this.serverCodecConfigurer = serverCodecConfigurer;
}
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE)
public ErrorWebExceptionHandler errorWebExceptionHandler(ErrorAttributes errorAttributes) {
GatewayExceptionHandler exceptionHandler = new GatewayExceptionHandler(errorAttributes, this.resourceProperties,
this.serverProperties.getError(), this.applicationContext);
exceptionHandler.setViewResolvers(this.viewResolvers);
exceptionHandler.setMessageWriters(this.serverCodecConfigurer.getWriters());
exceptionHandler.setMessageReaders(this.serverCodecConfigurer.getReaders());
return exceptionHandler;
}
}
修改后的返回结果
{
"code": 101,
"msg": "请求方式不被支持",
"payload": "",
"timestamp": 1565334087971
}
网友评论