Spring Cloud Gateway在有些場景中需要獲取request body內(nèi)容進行參數(shù)校驗或參數(shù)修改,我們通過在GatewayFilter中獲取請求內(nèi)容來獲取和修改請求體,下面我們就基于ServerWebExchange來實現(xiàn):
ServerWebExchange命名為服務(wù)網(wǎng)絡(luò)交換器,存放著重要的請求-響應(yīng)屬性、請求實例和響應(yīng)實例等等,有點像Context的角色,其中有兩個重要的接口方法:
// 獲取ServerHttpRequest對象
ServerHttpRequest getRequest();
// 獲取ServerHttpResponse對象
ServerHttpResponse getResponse();
創(chuàng)建一個GatewayFilter,必須實現(xiàn)Ordered接口,返回一個小于-1的order值,這是因為NettyWriteResponseFilter的order值為-1,我們需要覆蓋返回響應(yīng)體的邏輯,自定義的GlobalFilter必須比NettyWriteResponseFilter優(yōu)先執(zhí)行。
public class RequestGatewayFilter implements GatewayFilter, Ordered {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
HttpHeaders headers = request.getHeaders();
// 處理參數(shù)
MediaType contentType = headers.getContentType();
if (exchange.getRequest().getMethod().equals(HttpMethod.POST)) {
//Content-type為“application/json”
if (MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {
return readBody(exchange, chain);
}
//Content-type為“application/x-www-form-urlencoded”
else if(MediaType.APPLICATION_FORM_URLENCODED.isCompatibleWith(contentType)){
GatewayContext gatewayContext = new GatewayContext();
gatewayContext.setRequestHeaders(headers);
gatewayContext.getAllRequestData().addAll(request.getQueryParams());
exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT,gatewayContext);
return readFormData(exchange, chain, gatewayContext);
}
//Content-type為“multipart/form-data”
else if (MediaType.MULTIPART_FORM_DATA.isCompatibleWith(contentType)) {
GatewayContext gatewayContext = new GatewayContext();
gatewayContext.setRequestHeaders(headers);
gatewayContext.getAllRequestData().addAll(request.getQueryParams());
exchange.getAttributes().put(GatewayContext.CACHE_GATEWAY_CONTEXT,gatewayContext);
return readMultipartData(exchange, chain, gatewayContext);
}
} else {
return readGetData(exchange, chain);
}
return chain.filter(exchange);
}
@Override
public int getOrder() {
return -2;
}
}
處理content-type為application/json的方法:
/**
* ReadJsonBody
*
* @param exchange
* @param chain
* @return
*/
private Mono<Void> readBody(ServerWebExchange exchange, GatewayFilterChain chain) {
/**
* join the body
*/
return DataBufferUtils.join(exchange.getRequest().getBody()).flatMap(dataBuffer -> {
byte[] bytes = new byte[dataBuffer.readableByteCount()];
dataBuffer.read(bytes);
DataBufferUtils.release(dataBuffer);
/**
* validate request params or form data
*/
Result checkResult = null;
try {
String bodyString = new String(bytes, "utf-8");
Map bodyMap = JSONObject.parseObject(bodyString,Map.class);
//校驗參數(shù)
checkResult = validParam(exchange, bodyMap);
if(checkResult.getCode()!=0){
return errorInfo(exchange, checkResult.getCode(), checkResult.getMessage());
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
Flux<DataBuffer> cachedFlux = Flux.defer(() -> {
DataBuffer buffer = exchange.getResponse().bufferFactory().wrap(bytes);
DataBufferUtils.retain(buffer);
return Mono.just(buffer);
});
/**
* repackage ServerHttpRequest
*/
ServerHttpRequest mutatedRequest = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public Flux<DataBuffer> getBody() {
return cachedFlux;
}
};
ServerHttpResponse originalResponse = exchange.getResponse();
originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator response = buildResponse(originalResponse, bufferFactory, (Map)checkResult.getResult());
/**
* mutate exchage with new ServerHttpRequest
*/
ServerWebExchange mutatedExchange = exchange.mutate().request(mutatedRequest).response(response).build();
/**
* read body string with default messageReaders
*/
return ServerRequest.create(mutatedExchange, MESSAGE_READERS).bodyToMono(String.class)
.doOnNext(objectValue -> {
log.debug("[GatewayContext]Read JsonBody:{}", objectValue);
}).then(chain.filter(mutatedExchange));
});
}
處理content-type為application/x-www-form-urlencoded的方法:
/**
* ReadFormData
* @param exchange
* @param chain
* @return
*/
private Mono<Void> readFormData(ServerWebExchange exchange, GatewayFilterChain chain, GatewayContext gatewayContext){
HttpHeaders headers = exchange.getRequest().getHeaders();
return exchange.getFormData().switchIfEmpty(
Mono.defer(() -> Mono.just(new LinkedMultiValueMap<>()))
).flatMap(formDataMap -> {
Charset charset = headers.getContentType().getCharset();
charset = charset == null? StandardCharsets.UTF_8:charset;
String charsetName = charset.name();
MultiValueMap<String, String> paramMap = exchange.getRequest().getQueryParams();
Map map = convertMap(paramMap);
/*
* formData is empty just return
*/
if((null == formDataMap || formDataMap.isEmpty()) && (null == map || map.isEmpty())){
return chain.filter(exchange);
}
StringBuilder formDataBodyBuilder = new StringBuilder();
String entryKey;
List<String> entryValue;
try {
/*
* repackage form data
*/
for (Map.Entry<String, List<String>> entry : formDataMap.entrySet()) {
entryKey = entry.getKey();
entryValue = entry.getValue();
if (entryValue.size() > 1) {
for(String value : entryValue){
formDataBodyBuilder.append(entryKey).append("=").append(value).append("&");
}
} else {
formDataBodyBuilder.append(entryKey).append("=").append(entryValue.get(0)).append("&");
}
}
}catch (Exception e){
e.printStackTrace();
}
/*
* substring with the last char '&'
*/
String formDataBodyString = "";
if(formDataBodyBuilder.length()>0){
formDataBodyString = formDataBodyBuilder.substring(0, formDataBodyBuilder.length() - 1);
}
/*
* get data bytes
*/
byte[] bodyBytes = formDataBodyString.getBytes(charset);
int contentLength = bodyBytes.length;
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(exchange.getRequest().getHeaders());
httpHeaders.remove(HttpHeaders.CONTENT_LENGTH);
/*
* in case of content-length not matched
*/
httpHeaders.setContentLength(contentLength);
/**
* validate request params or form data
*/
Map<String, Object> bodyMap = StringUtils.isEmpty(formDataBodyString)?new HashMap<String, Object>():decodeFormBody(formDataBodyString);
Result checkResult = validParam(exchange, bodyMap);
if(checkResult.getCode()!=0){
return errorInfo(exchange, checkResult.getCode(), checkResult.getMessage());
}
/*
* use BodyInserter to InsertFormData Body
*/
BodyInserter<String, ReactiveHttpOutputMessage> bodyInserter = BodyInserters.fromObject(formDataBodyString);
CachedBodyOutputMessage cachedBodyOutputMessage = new CachedBodyOutputMessage(exchange, httpHeaders);
log.debug("[GatewayContext]Rewrite Form Data :{}",formDataBodyString);
return bodyInserter.insert(cachedBodyOutputMessage, new BodyInserterContext())
.then(Mono.defer(() -> {
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(
exchange.getRequest()) {
@Override
public HttpHeaders getHeaders() {
return httpHeaders;
}
@Override
public Flux<DataBuffer> getBody() {
return cachedBodyOutputMessage.getBody();
}
};
ServerHttpResponse originalResponse = exchange.getResponse();
originalResponse.getHeaders().setContentType(MediaType.APPLICATION_JSON);
DataBufferFactory bufferFactory = originalResponse.bufferFactory();
ServerHttpResponseDecorator response = buildResponse(originalResponse, bufferFactory, (Map)checkResult.getResult());
return chain.filter(exchange.mutate().request(decorator).response(response).build());
}));
});
}
有時需要對返回的數(shù)據(jù)統(tǒng)一處理,那么可以通過封裝ServerHttpResponseDecorator進行處理,ServerHttpResponse裝飾器ServerHttpResponseDecorator,主要覆蓋寫入響應(yīng)體數(shù)據(jù)緩沖區(qū)的部分。文章來源:http://www.zghlxwxcb.cn/news/detail-559622.html
private ServerHttpResponseDecorator buildResponse(ServerHttpResponse originalResponse, DataBufferFactory bufferFactory, Map result) {
return new ServerHttpResponseDecorator(originalResponse) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
System.out.println("++++++++++++++++++++++++1");
if (getStatusCode().equals(HttpStatus.OK) && body instanceof Flux) {
Flux<? extends DataBuffer> fluxBody = Flux.from(body);
return super.writeWith(fluxBody.buffer().map(dataBuffers -> {
DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();
DataBuffer join = dataBufferFactory.join(dataBuffers);
byte[] content = new byte[join.readableByteCount()];
join.read(content);
DataBufferUtils.release(join);
// 流轉(zhuǎn)為字符串
String responseData = new String(content, Charsets.UTF_8);
System.out.println(responseData);
Map map = JSON.parseObject(responseData);
//處理返回的數(shù)據(jù)
//To do
byte[] uppedContent = responseData.getBytes(Charsets.UTF_8);
originalResponse.getHeaders().setContentLength(uppedContent.length);
return bufferFactory.wrap(uppedContent);
}));
} else {
System.out.println("----------"+getStatusCode());
}
return super.writeWith(body);
}
@Override
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return writeWith(Flux.from(body).flatMapSequential(p -> p));
}
};
}
更多接口、代碼工具、開發(fā)資源請訪問昂焱數(shù)據(jù):https://www.ayshuju.com文章來源地址http://www.zghlxwxcb.cn/news/detail-559622.html
到了這里,關(guān)于SpringCloud GateWay通過過濾器GatewayFilter修改請求或響應(yīng)內(nèi)容的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!