话不多说,直接上码
/**
* @author liuhanling
* @create 2018-12-14 20:01
* @desc
*/
@Slf4j
@Component
public class RequestBodyFilter implements GatewayFilter, Ordered {
private static final String CACHE_REQUEST_BODY_OBJECT_KEY = "cachedRequestBodyObject";
@Override
@SuppressWarnings("unchecked")
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
Class inClass = String.class;
ServerRequest serverRequest = new DefaultServerRequest(exchange);
ServerHttpRequest request = exchange.getRequest();
//只记录 http 请求(包含 https)
String schema = request.getURI().getScheme();
if ((!"http".equals(schema) && !"https".equals(schema))) {
return chain.filter(exchange);
}
String contentType = request.getHeaders().getFirst("Content-Type");
String upload = request.getHeaders().getFirst("upload");
//get 方法获取参数
if ("GET".equals(request.getMethod().name())) {
if (!request.getQueryParams().isEmpty()) {
Map<String, String> map = new HashMap<>();
request.getQueryParams().toSingleValueMap().forEach((key, val) -> map.put(key, getURLDecoder(val)));
String param = new Gson().toJson(map);
exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, param);
}
return chain.filter(exchange);
}
//没有内容类型不读取body
if (contentType == null || contentType.length() == 0) {
return chain.filter(exchange);
}
//文件上传不读取body
if ("true".equals(upload)) {
return chain.filter(exchange);
}
Mono<?> modifiedBody = serverRequest.bodyToMono(inClass).flatMap(o -> {
log.debug("requestBody:{}", o);
exchange.getAttributes().put(CACHE_REQUEST_BODY_OBJECT_KEY, o);
return Mono.justOrEmpty(o);
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, inClass);
HttpHeaders headers = new HttpHeaders();
headers.putAll(exchange.getRequest().getHeaders());
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, headers);
return bodyInserter.insert(outputMessage, new BodyInserterContext())
.then(Mono.defer(() -> {
ServerHttpRequestDecorator decorator = new ServerHttpRequestDecorator(exchange.getRequest()) {
@Override
public HttpHeaders getHeaders() {
long contentLength = headers.getContentLength();
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.putAll(super.getHeaders());
if (contentLength > 0) {
httpHeaders.setContentLength(contentLength);
} else {
// TODO: this causes a 'HTTP/1.1 411 Length Required' on httpbin.org
httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked");
}
return httpHeaders;
}
@Override
public Flux<DataBuffer> getBody() {
return outputMessage.getBody();
}
};
return chain.filter(exchange.mutate().request(decorator).build());
}));
}
@Override
public int getOrder() {
return 0;
}
/**
* URL 转码
* @param val
* @return
*/
private String getURLDecoder(String val){
try{
return URLDecoder.decode(val, "utf-8");
}catch (Exception e){
log.error("getURLDecoder error",e);
}
return val;
}
}
重写 ResponseBody
/**
* @author liuhanling
* @create 2018-12-27 10:39
* @desc
*/
@Component
@Slf4j
public class ResponseBodyFilter implements GatewayFilter, Ordered {
@Override
@SuppressWarnings("unchecked")
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpResponseDecorator responseDecorator = new ServerHttpResponseDecorator(exchange.getResponse()) {
@Override
public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
Class inClass = String.class;
Class outClass = String.class;
String originalResponseContentType = exchange.getAttribute(ORIGINAL_RESPONSE_CONTENT_TYPE_ATTR);
HttpHeaders httpHeaders = new HttpHeaders();
//explicitly add it in this way instead of 'httpHeaders.setContentType(originalResponseContentType)'
//this will prevent exception in case of using non-standard media types like "Content-Type: image"
httpHeaders.add(HttpHeaders.CONTENT_TYPE, originalResponseContentType);
ResponseAdapter responseAdapter = new ResponseAdapter(body, httpHeaders);
DefaultClientResponse clientResponse = new DefaultClientResponse(responseAdapter, ExchangeStrategies.withDefaults());
//TODO: flux or mono
Mono modifiedBody = clientResponse.bodyToMono(inClass)
.flatMap(originalBody -> {
//如果是文件
Gson gson = new Gson();
Map<String,String> res = gson.fromJson(String.valueOf(originalBody),new TypeToken<HashMap<String, String>>() {}.getType());
//修改
res.put("test_id",UUID.randomUUID().toString().replace("-",""));
return Mono.just(gson.toJson(res));
});
BodyInserter bodyInserter = BodyInserters.fromPublisher(modifiedBody, outClass);
CachedBodyOutputMessage outputMessage = new CachedBodyOutputMessage(exchange, exchange.getResponse().getHeaders());
return bodyInserter.insert(outputMessage, new BodyInserterContext())
.then(Mono.defer(() -> {
Flux<DataBuffer> messageBody = outputMessage.getBody();
//TODO: if (inputStream instanceof Mono) {
HttpHeaders headers = getDelegate().getHeaders();
if (!headers.containsKey(HttpHeaders.TRANSFER_ENCODING)) {
messageBody = messageBody.doOnNext(data -> headers.setContentLength(data.readableByteCount()));
}
// }
//TODO: use isStreamingMediaType?
return getDelegate().writeWith(messageBody);
}));
}
@Override
public Mono<Void> writeAndFlushWith(Publisher<? extends Publisher<? extends DataBuffer>> body) {
return writeWith(Flux.from(body)
.flatMapSequential(p -> p));
}
};
return chain.filter(exchange.mutate().response(responseDecorator).build());
}
@Override
public int getOrder() {
return 0;
}
public class ResponseAdapter implements ClientHttpResponse {
private final Flux<DataBuffer> flux;
private final HttpHeaders headers;
public ResponseAdapter(Publisher<? extends DataBuffer> body, HttpHeaders headers) {
this.headers = headers;
if (body instanceof Flux) {
flux = (Flux) body;
} else {
flux = ((Mono)body).flux();
}
}
@Override
public Flux<DataBuffer> getBody() {
return flux;
}
@Override
public HttpHeaders getHeaders() {
return headers;
}
@Override
public HttpStatus getStatusCode() {
return null;
}
@Override
public int getRawStatusCode() {
return 0;
}
@Override
public MultiValueMap<String, ResponseCookie> getCookies() {
return null;
}
}
}
版本信息
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.2.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR2</spring-cloud.version>
</properties>
理论部分参考: https://blog.51cto.com/thinklili/2329184
来源:51CTO
作者:liuhanling
链接:https://blog.51cto.com/5634409/2343489