如何在Zuul后置滤波器中获得响应体?

时间:2016-01-29 15:48:07

标签: java proxy netflix-zuul

post过滤器中使用Zuul作为代理时如何读取响应正文?

我试图像这样调用代码:

@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;
    }

}

7 个答案:

答案 0 :(得分:11)

我设法克服了这一点。解决方案包括4个步骤:

  1. ctx.getResponseDataStream()读入ByteArrayOutputStream
  2. 将OutputStream复制到2个InputStreams。
  3. 将其中一个用于自定义目的。
  4. 使用秒来重新分配上下文:context.setResponseBody(inputStream)
    • 从第1点读取流会导致无法再次读取流,因此这样您就可以传递尚未读取的新流

答案 1 :(得分:3)

正如您在此example中所看到的,您有两种方法可用于提取响应正文:

1- ctx.getResponseBody();

2- ctx.getResponseDataStream();

你必须检查哪一个不为空并使用那个。

答案 2 :(得分:3)

感谢您的建议,这是我使用的代码。

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);
}

答案 3 :(得分:1)

小心filterNumber

  

使用大于1000的任何内容都会导致“InputStream”   关闭“错误,因为响应正文已被阅读

我使用数字10并且工作正常

答案 4 :(得分:1)

如果有人在压缩答案中苦苦挣扎,这就是我使用的解决方案:

// 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);
}

答案 5 :(得分:0)

没有一个答案对我有用。 1)过滤器的阶数必须低于1000(发送响应过滤器)

2)代码:

 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;
}

答案 6 :(得分:0)

最简单的解决方案是获取一个输入流,用InputStreamReader读取它,最后根据读取的字符串创建一个新的流并将其设置为上下文的响应数据流。另外,不要忘记将过滤器的顺序设置为低于 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);