很多朋友在使用SpringCloudGateway的時候可能都碰到過以下幾個問題
SpringCloudGateway中如何讀取Post請求體
private BodyInserter getBodyInserter(ServerWebExchange exchange) {
ServerRequest serverRequest = new DefaultServerRequest(exchange);
Mono<String> modifiedBody = serverRequest.bodyToMono(String.class)
.flatMap(body -> {
//這里的body就是Post的請求體
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, String.class);
return bodyInserter;
}
SpringCloudGateway中Post請求參數只能讀取一次
這是因為Gateway默認使用的是SpringWebflux,解決這個問題需要容重新構造一個request來替換原先的request
HttpHeaders headers=new HttpHeaders();
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
ServerHttpRequestDecorator decorator = this.getServerHttpRequestDecorator(exchange,outputMessage);
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(
exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return outputMessage.getBody();
}
};
當ServerHttpRequestDecorator構建完成之后需要在攔截器中使用如下方法替換原先的request
return chain.filter(exchange.mutate().request(decorator).build());
SpringCloudGateway中如何讀取后段服務的返回數據
與上方替換request的思路一致,替換response即可
private ServerHttpResponse getServerHttpResponse(ServerWebExchange exchange) {
ServerHttpResponse originalResponse = exchange.getResponse();
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
Flux<DataBuffer> flux = null;
if (body instanceof Mono) {
Mono<? extends DataBuffer> mono = (Mono<? extends DataBuffer>) body;
body = mono.flux();
}
if (body instanceof Flux) {
flux = (Flux<DataBuffer>) body;
return super.writeWith(flux.buffer().map(dataBuffers -> {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
dataBuffers.forEach(i -> {
byte[] array = new byte[i.readableByteCount()];
i.read(array);
DataBufferUtils.release(i);
outputStream.write(array, 0, array.length);
});
String result = outputStream.toString();
try {
if (outputStream != null) {
outputStream.close();
}
} catch (IOException e) {
e.printStackTrace();
}
log.info("后端返回數據:{}", result);
return bufferFactory.wrap(result.getBytes());
}));
}
log.info("降級處理返回數據:{}" + body);
return super.writeWith(body);
}
};
return decoratedResponse;
}
上方是獲取新的response,獲取到新的之后和之前的套路一樣,這樣操作:
return chain.filter(exchange.mutate().request(decorator).response(decoratedResponse).build());
可能有的同學會碰到即使按照我上述的方法重寫了response但是也無法讀取到返回數據,這個原因可能是因為攔截器的優先級配置有問題,只需要實現Ordered接口並且重寫getOrder方法,然后設置優先級小於-1即可
@Override
public int getOrder() {
return -2;
}