How it is possible to read a response body while using Zuul as a proxy in post
filter?
I am trying to call the code like this:
@Component
public class PostFilter extends ZuulFilter {
private static final Logger log = LoggerFactory.getLogger(PostFilter.class);
@Override
public String filterType() {
return "post";
}
@Override
public int filterOrder() {
return 2000;
}
@Override
public boolean shouldFilter() {
return true;
}
@Override
public Object run() {
RequestContext ctx = RequestContext.getCurrentContext();
ctx.getResponseBody(); // null
// cant't do this, cause input stream is used later in other filters and I got InputStream Closed exception
// GZIPInputStream gzipInputStream = new GZIPInputStream(stream);
return null;
}
}
I've managed to overcome this. The solution consists of 4 steps:
ctx.getResponseDataStream()
into a ByteArrayOutputStream context.setResponseBody(inputStream)
If someone is struggling with compressed answer, here's the solution I used:
// Read the compressed response
RequestContext ctx = RequestContext.getCurrentContext();
InputStream compressedResponseDataStream = ctx.getResponseDataStream();
try {
// Uncompress and transform the response
InputStream responseDataStream = new GZIPInputStream(compressedResponseDataStream);
String responseAsString = StreamUtils.copyToString(responseDataStream, Charset.forName("UTF-8"));
// Do want you want with your String response
...
// Replace the response with the modified object
ctx.setResponseBody(responseAsString);
} catch (IOException e) {
logger.warn("Error reading body", e);
}
Thanks for suggestion, this is the code I used that works.
try (final InputStream responseDataStream = ctx.getResponseDataStream()) {
final String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
ctx.setResponseBody(responseData);
} catch (IOException e) {
logger.warn("Error reading body",e);
}
As you can see in this example , you have two methods available to extract the response body:
1- ctx.getResponseBody();
2- ctx.getResponseDataStream();
You have to check which one is not null and use that one.
Be careful with the filterNumber
Using anything greater than 1000 leads to an "InputStream already closed" error because the response body has already been read and
I used the number 10 and worked fine
None of the answers worked for me. 1) Order of the filter needs to be lower that 1000 (sending response filter)
2) Code:
private String getResponseData(RequestContext ctx) throws IOException {
String responseData = null;
final InputStream responseDataStream = ctx.getResponseDataStream();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayOutputStream copy = new ByteArrayOutputStream();
int read = 0;
byte[] buff = new byte[1024];
while ((read = responseDataStream.read(buff)) != -1) {
bos.write(buff, 0, read);
copy.write(buff, 0, read);
}
InputStream isFromFirstData = new ByteArrayInputStream(bos.toByteArray());
boolean responseGZipped = ctx.getResponseGZipped();
try {
InputStream zin = null;
if (responseGZipped) {
zin = new GZIPInputStream(isFromFirstData);
} else {
zin = responseDataStream;
}
responseData = CharStreams.toString(new InputStreamReader(zin, "UTF-8"));
ctx.setResponseDataStream(new ByteArrayInputStream(copy.toByteArray()));
} catch (IOException e) {
logger.warn("Error reading body {}", e.getMessage());
}
return responseData;
}
The simplest solution would be to get an input stream, read it with InputStreamReader
, and finally create a new stream based on the read string and set it as a response data stream of context. Also, don't forget to set the order of the filter to number lower then 1000.
final InputStream responseDataStream = ctx.getResponseDataStream();
String response = CharStreams.toString(new InputStreamReader(responseDataStream, StandardCharsets.UTF_8));
InputStream stream = new ByteArrayInputStream(response.getBytes(StandardCharsets.UTF_8));
ctx.setResponseDataStream(stream);
//NOTE:filterOrder:999
RequestContext context = getCurrentContext();
InputStream stream = context.getResponseDataStream();
// uncompress
String body = StreamUtils.copyToString(new GZIPInputStream(stream),
Charset.forName("UTF-8"));
// modify
body = "Modified gzipped response via setResponseBody(): " + body;
// compress again
ByteArrayOutputStream bos = new ByteArrayOutputStream(body.length());
GZIPOutputStream gzip = new GZIPOutputStream(bos);
gzip.write(body.getBytes("UTF-8"));
gzip.close();
byte[] compressed = bos.toByteArray();
bos.close();
context.setResponseDataStream(new ByteArrayInputStream(compressed));
https://github.com/spring-attic/sample-zuul-filters/issues/4
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.