前言 spring boot升级到2.x之后 对于request和response的增强方式发生了变化 由于spring boot2.x 不仅仅有servlet标准容器 还有一些其他类型的容器 如netty
实例 增强request 继承ServerHttpRequestDecorator 实现对于 serverHttpRequest的增强
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 import com.ming.base.GlobalConstant;import com.ming.core.utils.DataBufferUtils;import lombok.Getter;import lombok.extern.slf4j.Slf4j;import org.apache.commons.lang.StringUtils;import org.springframework.core.io.buffer.DataBuffer;import org.springframework.http.HttpMethod;import org.springframework.http.MediaType;import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.http.server.reactive.ServerHttpRequestDecorator;import reactor.core.publisher.Flux;import java.util.Optional;import java.util.stream.Collectors;import static reactor.core.scheduler.Schedulers.single;@Slf4j @Getter public class RequestWrapper extends ServerHttpRequestDecorator { public static final ImmutableList<MediaType> NEED_LOG_MEDIA_TYPES = ImmutableList.<MediaType>builder() .add(MediaType.TEXT_XML) .add(MediaType.APPLICATION_XML) .add(MediaType.APPLICATION_JSON) .add(MediaType.TEXT_PLAIN) .add(MediaType.TEXT_XML) .build(); private Flux<DataBuffer> body; public RequestWrapper (ServerHttpRequest delegate) { super (delegate); final String path = delegate.getURI().getPath(); final String query = delegate.getURI().getQuery(); final String method = Optional.ofNullable(delegate.getMethod()).orElse(HttpMethod.GET).name(); final String headers = delegate.getHeaders().entrySet() .stream() .map(entry -> "" + entry.getKey() + ": [" + String.join(";" , entry.getValue()) + "]" ) .collect(Collectors.joining("\n" )); final MediaType contentType = delegate.getHeaders().getContentType(); log.info("HttpMethod:{},Uri:{},Headers:{}" , method, path + (StringUtils.isEmpty(query) ? "" : "?" + query), headers); Flux<DataBuffer> flux = super .getBody(); if (NEED_LOG_MEDIA_TYPES.contains(contentType)) { body = flux.publishOn(single()).map(dataBuffer -> { byte [] bodyByteArr = DataBufferUtils.readDataBuffer(dataBuffer); log.info("requestBody:{}" , com.ming.core.utils.StringUtils.valueOfByUtf8(bodyByteArr)); return DataBufferUtils.refillDataBuffer(dataBuffer, bodyByteArr); }); } else { body = flux; } } }
增强response 继承ServerHttpResponseDecorator 实现增强serverHttpResponse
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 import com.ming.base.GlobalConstant;import com.ming.core.utils.DataBufferUtils;import com.ming.core.utils.StringUtils;import lombok.extern.slf4j.Slf4j;import org.reactivestreams.Publisher;import org.springframework.core.io.buffer.DataBuffer;import org.springframework.http.MediaType;import org.springframework.http.server.reactive.ServerHttpResponse;import org.springframework.http.server.reactive.ServerHttpResponseDecorator;import reactor.core.publisher.Flux;import reactor.core.publisher.Mono;import static reactor.core.scheduler.Schedulers.single;@Slf4j public class ResponseWrapper extends ServerHttpResponseDecorator { ResponseWrapper(ServerHttpResponse delegate) { super (delegate); } @Override @SuppressWarnings("unchecked") public Mono<Void> writeWith (Publisher<? extends DataBuffer> body) { final MediaType contentType = super .getHeaders().getContentType(); if (GlobalConstant.NEED_LOG_MEDIA_TYPES.contains(contentType)) { if (body instanceof Mono) { final Mono<DataBuffer> monoBody = (Mono<DataBuffer>) body; return super .writeWith(monoBody.publishOn(single()).map(dataBuffer -> { byte [] bodyByteArr = DataBufferUtils.readDataBuffer(dataBuffer); log.info("mono->responseBody:{}" , StringUtils.valueOfByUtf8(bodyByteArr)); return DataBufferUtils.refillDataBuffer(dataBuffer, bodyByteArr); })); } else if (body instanceof Flux) { final Flux<DataBuffer> fluxBody = (Flux<DataBuffer>) body; return super .writeWith(fluxBody.publishOn(single()).map(dataBuffer -> { byte [] bodyByteArr = DataBufferUtils.readDataBuffer(dataBuffer); log.info("flux->responseBody:{}" , StringUtils.valueOfByUtf8(bodyByteArr)); return DataBufferUtils.refillDataBuffer(dataBuffer, bodyByteArr); })); } } return super .writeWith(body); } }
增强exchange 继承 ServerWebExchangeDecorator 实现增强exchange 引用增强的request、response
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import org.springframework.http.server.reactive.ServerHttpRequest;import org.springframework.http.server.reactive.ServerHttpResponse;import org.springframework.web.server.ServerWebExchange;import org.springframework.web.server.ServerWebExchangeDecorator;public class ExchangeWrapper extends ServerWebExchangeDecorator { private RequestWrapper requestDecorator; private ResponseWrapper responseDecorator; public ExchangeWrapper (ServerWebExchange delegate) { super (delegate); requestDecorator = new RequestWrapper (delegate.getRequest()); responseDecorator = new ResponseWrapper (delegate.getResponse()); } @Override public ServerHttpRequest getRequest () { return requestDecorator; } @Override public ServerHttpResponse getResponse () { return responseDecorator; } }
在filter中使用增强的request,response,exchange 实现spring抽象的webFilter 来对请求的exchange request response 进行增强处理
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import lombok.extern.slf4j.Slf4j;import org.springframework.context.annotation.Configuration;import org.springframework.web.server.ServerWebExchange;import org.springframework.web.server.WebFilter;import org.springframework.web.server.WebFilterChain;import reactor.core.publisher.Mono;@Configuration @Slf4j public class Filter implements WebFilter { @Override public Mono<Void> filter (ServerWebExchange serverWebExchange, WebFilterChain chain) { return chain.filter(new ExchangeWrapper (serverWebExchange)); } }
总结 java web中 spring 框架提供对http的请求响应的包装 默认的功能不是很多 大部分时候 需要借用spring 框架预留的口子 进行增强来处理一些对http请求的操作 例如 读取requestBody responseBody 等