Spring Cloud Gateway 作為微服務(wù)的最前沿氮发,可以實現(xiàn)限流、鑒權(quán)等等操作冗懦,本文將以修改統(tǒng)一格式的返回參數(shù)作為講解
新建GlobalFilter的實現(xiàn)類
Spring 修改前的默認返回參數(shù)如下
{
"status": 404,
"error":"",
"message": "NOT FUND",
"path": "/test",
"timestamp": 1565334087971
}
@Slf4j
@Component
public class OpenGatewayFilter implements GlobalFilter, Ordered {
/** 將 List 數(shù)據(jù)以""分隔進行拼接 **/
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 針對返回參數(shù)過長的情況下會分段返回爽冕,使用如下方式接受返回參數(shù)則可避免
dataBuffers.forEach(dataBuffer -> {
// probably should reuse buffers
byte[] content = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(content);
// 釋放掉內(nèi)存
DataBufferUtils.release(dataBuffer);
list.add(new String(content, StandardCharsets.UTF_8));
});
// 將多次返回的參數(shù)拼接起來
String responseData = joiner.join(list);
// 重置返回參數(shù)
String result = response(responseData);
byte[] uppedContent =
new String(result.getBytes(StandardCharsets.UTF_8), StandardCharsets.UTF_8).getBytes();
// 修改后的返回參數(shù)應該重置長度,否則如果修改后的參數(shù)長度超出原始參數(shù)長度時會導致客戶端接收到的參數(shù)丟失一部分
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("轉(zhuǎn)換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;
}
}
修改后的返回結(jié)果
{
"code": 101,
"msg": "請求方式不被支持",
"payload": "",
"timestamp": 1565334087971
}