文章目录
- 前言
- 一、获取响应数据并打印
前言
我们的网关在之前只记录了接口请求日志,响应日志是没有做记录的,在后续别人对接我们开放平台时出现了一些问题没法确认当时的一个数值状态,照成了很多不必要的麻烦,后来决定在网关添加上响应日志记录。
一、获取响应数据并打印
import lombok.extern.slf4j.Slf4j;
import org.reactivestreams.Publisher;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferFactory;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.DefaultDataBufferFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.http.server.reactive.ServerHttpResponseDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;import java.nio.charset.Charset;@Slf4j
@Component
public class ResponseLogGlobalFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {try {ServerHttpResponse originalResponse = exchange.getResponse();DataBufferFactory bufferFactory = originalResponse.bufferFactory();ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) {@Overridepublic Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {if (body instanceof Flux) {Flux<? extends DataBuffer> fluxBody = Flux.from(body);return super.writeWith(fluxBody.buffer().map(dataBuffers -> {// 合并多个流集合,解决返回体分段传输DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory();DataBuffer buff = dataBufferFactory.join(dataBuffers);byte[] content = new byte[buff.readableByteCount()];buff.read(content);DataBufferUtils.release(buff);//释放掉内存//排除Excel导出,不是application/json不打印MediaType contentType = originalResponse.getHeaders().getContentType();if (!MediaType.APPLICATION_JSON.isCompatibleWith(contentType)) {return bufferFactory.wrap(content);}// 想要关联请求和响应日志可以添加自定义请求头(我这里会在打印请求日志的过滤器中添加REUQEST_ID头来关联响应日志)String reuqestId = exchange.getRequest().getHeaders().getFirst("REUQEST_ID");// content就是response的值,可以查看和修改String contentStr = new String(content, Charset.forName("UTF-8"));log.info("reuqestId={} contentStr={}",reuqestId,contentStr);getDelegate().getHeaders().setContentLength(contentStr.getBytes().length);return bufferFactory.wrap(contentStr.getBytes());}));} else {log.error("<-- {} 响应code异常", getStatusCode());}return super.writeWith(body);}};return chain.filter(exchange.mutate().response(decoratedResponse).build());} catch (Exception e) {log.error("gateway log exception e={}", e);return chain.filter(exchange);}}@Overridepublic int getOrder() {return -1;}
}