赞
踩
网关用springcloud gateway路由调用接口,现在需要获取到接口响应数据并做修改。遇到如下几个问题:
1.用postman调用接口没有响应,后端也没报错信息;
2.有响应数据但数据不完整,解析出错;
3.数据响应类型丢失。
头一回用springcloud gateway就遇到这几个问题,困扰好久不过也是长知识了。下面则是我的解决办法,亲测可用,如有不完善的地方请多指教。
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.cloud.gateway.filter.NettyWriteResponseFilter; 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.HttpHeaders; 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.StandardCharsets; @Slf4j @Component public class TestFilter implements GlobalFilter, Ordered { @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { ServerHttpResponse originalResponse = exchange.getResponse(); DataBufferFactory bufferFactory = originalResponse.bufferFactory(); // 定义新的消息头 HttpHeaders headers = new HttpHeaders(); headers.putAll(exchange.getResponse().getHeaders()); //在ServerHttpResponseDecorator 这个类里面实现对响应数据的处理,复写writeWith()和 getHeaders()两个方法 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.buffer().map(dataBuffer -> { //过滤器后置逻辑 //上面第2个问题是因为响应体数据量太大,分段截取时造成的数据错误问题 //使用dataBufferFactory.join解决该问题 DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); DataBuffer join = dataBufferFactory.join(dataBuffer); byte[] content = new byte[join.readableByteCount()]; join.read(content); //释放掉内存 DataBufferUtils.release(join); //实际获取到的响应数据 String responseStr = new String(content, StandardCharsets.UTF_8); //这里 自定义一个新的响应数据,作为返回数据,相当于修改响应体 String newResponseStr = "{\"hhhh\":666}"; byte[] newResponseBytes = newResponseStr.getBytes(StandardCharsets.UTF_8); // 给header设置长度 解决上面第1个无响应数据的问题 headers.setContentLength(newResponseBytes.length); HttpHeaders httpHeaders = originalResponse.getHeaders(); //设置响应体类型 Content-Type 解决第3个问题 httpHeaders.add("Content-Type", "application/json; charset=UTF-8"); //newResponseBytes是修改之后要返回的响应体数据 return bufferFactory.wrap(newResponseBytes); })); } return super.writeWith(body); } @Override public HttpHeaders getHeaders() { HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.putAll(super.getHeaders()); //由于修改了请求体的body,导致content-length长度不确定,因此使用分块编码 httpHeaders.remove(HttpHeaders.CONTENT_LENGTH); httpHeaders.set(HttpHeaders.TRANSFER_ENCODING, "chunked"); return httpHeaders; } }; return chain.filter(exchange.mutate().response(decoratedResponse).build()); } @Override public int getOrder() { //order越小越先执行 当前Filter要在NettyWriteResponseFilter 之前运行 return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER - 1; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。