Awara 2019-06-30
(1)一开始搜索读取参数的文章,方法大多是从body里读一次DataBuffer,转成字符串,然后再把字符串转成DataBuffer重新放到body里,如:
http://www.cnblogs.com/cafeba...
(2)
上面的方法我试过可以,但是Content-Type是multipart/form-data的时候会报错 java.lang.IllegalStateException: Only one connection receive subscriber allowed. 不知道是不是我姿势不对。 而且如果我们在代理到第三方服务的时候才读取body,这样效率应该会高一些 看NettyRoutingFilter类里的filter方法 public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ······· Mono<HttpClientResponse> responseMono = this.httpClient.request(method, url, req -> { final HttpClientRequest proxyRequest = req.options(NettyPipeline.SendOptions::flushOnEach) .headers(httpHeaders) .chunkedTransfer(chunkedTransfer) .failOnServerError(false) .failOnClientError(false); if (preserveHost) { String host = request.getHeaders().getFirst(HttpHeaders.HOST); proxyRequest.header(HttpHeaders.HOST, host); } if (properties.getResponseTimeout() != null) { proxyRequest.context(ctx -> ctx.addHandlerFirst( new ReadTimeoutHandler(properties.getResponseTimeout().toMillis(), TimeUnit.MILLISECONDS))); } return proxyRequest.sendHeaders() //这里的是ReactorServerHttpRequest调用了getBody()方法, //所以我们只要重写ReactorServerHttpRequest的getbody方法,加上我们读取的逻辑就行了, //gateway给我们提供了装饰类ServerHttpRequestDecorator,我们只需把过滤器的优先级设置高于NettyRoutingFilter(实际他已经是倒数第二的优先级了),且把ReactorServerHttpRequest替换成ServerHttpRequestDecorator就行了 .send(request.getBody().map(dataBuffer -> ((NettyDataBuffer) dataBuffer).getNativeBuffer())); }); 给个stackoverflow的伪代码 ServerHttpRequestDecorator decoratedRequest = new ServerHttpRequestDecorator(request) { @Override public Flux<DataBuffer> getBody() { StringBuilder sb=new StringBuilder(); return super.getBody().map(dataBuffer -> { // probably should reuse buffers byte[] content = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(content); byte[] uppedContent = new String(content, Charset.forName("UTF-8")).toUpperCase().getBytes(); return bufferFactory.wrap(uppedContent); }) ; } }; //再说说记录返回的json,在NettyRoutingFilter类的154行,请求第三方服务反回后, // Defer committing the response until all route filters have run // Put client response as ServerWebExchange attribute and write response later NettyWriteResponseFilter //注释说了把返回结果放进ServerWebExchange 的参数里了,并且在NettyWriteResponseFilter读取 exchange.getAttributes().put(CLIENT_RESPONSE_ATTR, res); 看NettyWriteResponseFilter的读取代码, public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { return chain.filter(exchange).then(Mono.defer(() -> { //拿出NettyRoutingFilter放进去的Response HttpClientResponse clientResponse = exchange.getAttribute(CLIENT_RESPONSE_ATTR); if (clientResponse == null) {//空的就不过直接到下一个过滤器 return Mono.empty(); } log.trace("NettyWriteResponseFilter start"); ServerHttpResponse response = exchange.getResponse(); NettyDataBufferFactory factory = (NettyDataBufferFactory) response.bufferFactory(); //TODO: what if it's not netty final Flux<NettyDataBuffer> body = clientResponse.receive() .retain() //TODO: needed? .map(factory::wrap); MediaType contentType = null; try { contentType = response.getHeaders().getContentType(); } catch (Exception e) { log.trace("invalid media type", e); } //判断contentType是不是text/event-stream或者application/stream+json //反正上面两种类型的结果我们肯定不用记录,所以我们重写response的writeWith方法就好, //跟上面一样gateway也提供了个装饰器类ServerHttpResponseDecorator return (isStreamingMediaType(contentType) ? response.writeAndFlushWith(body.map(Flux::just)) : response.writeWith(body)); })); } 上stackoverflow的伪代码 DataBufferFactory bufferFactory = originalResponse.bufferFactory(); ServerHttpResponseDecorator decoratedResponse = new ServerHttpResponseDecorator(originalResponse) { @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) { if (body instanceof Flux) { Flux<? extends DataBuffer> fluxBody = (Flux<? extends DataBuffer>) body; return super.writeWith(fluxBody.map(dataBuffer -> { // probably should reuse buffers byte[] content = new byte[dataBuffer.readableByteCount()]; dataBuffer.read(content); byte[] uppedContent = new String(content, Charset.forName("UTF-8")).toUpperCase().getBytes(); return bufferFactory.wrap(uppedContent); })); } return super.writeWith(body); // if body is not a flux. never got there. } };
参考:
https://stackoverflow.com/que...
该如果返回的数据长度很长的话,数据可能会读不完全,如果出现读取时截取了中文字符,导致长度变多1位,进而json的右括号消失,也可参考下面链接
参考解决方案:
https://stackoverflow.com/que...