简体   繁体   English

如何在 Zuul 后置过滤器中获取响应正文?

[英]How to get response body in Zuul post filter?

How it is possible to read a response body while using Zuul as a proxy in post filter?post过滤器中使用 Zuul 作为代理时如何读取响应正文?

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:解决方案包括 4 个步骤:

  1. Read ctx.getResponseDataStream() into a ByteArrayOutputStream ctx.getResponseDataStream()读入 ByteArrayOutputStream
  2. Copy OutputStream to 2 InputStreams.将 OutputStream 复制到 2 个 InputStreams。
  3. Use one of it for your custom purposes.将其中之一用于您的自定义目的。
  4. Use the second to reassign to context: context.setResponseBody(inputStream)使用第二个重新分配给上下文: context.setResponseBody(inputStream)
    • reading stream from point 1 would cause that the stream cannot be read again, so this way you're passing a new fresh stream that wasn't read yet从第 1 点读取流会导致无法再次读取流,因此通过这种方式,您将传递一个尚未读取的新流

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(); 1- ctx.getResponseBody();

2- ctx.getResponseDataStream(); 2- ctx.getResponseDataStream();

You have to check which one is not null and use that one.您必须检查哪一个不为空并使用那个。

Be careful with the filterNumber小心使用 filterNumber

Using anything greater than 1000 leads to an "InputStream already closed" error because the response body has already been read and使用大于 1000 的值会导致“InputStream 已关闭”错误,因为响应正文已被读取并且

I used the number 10 and worked fine我使用了数字 10 并且工作正常

None of the answers worked for me.没有一个答案对我有用。 1) Order of the filter needs to be lower that 1000 (sending response filter) 1)过滤器的顺序需要低于1000(发送响应过滤器)

2) Code: 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;
}

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.最简单的解决方案是获取一个输入流,使用InputStreamReader读取它,最后根据读取的字符串创建一个新流并将其设置为上下文的响应数据流。 Also, don't forget to set the order of the filter to number lower then 1000.另外,不要忘记将过滤器的顺序设置为低于 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/4https://github.com/spring-attic/sample-zuul-filters/issues/4

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 Zuul 后置过滤器中拦截和编辑响应正文? - How to intercept and edit response body in Zuul post filter? 如何使用zuul将响应主体提取到后过滤器中 - How to extract the response body into post filter using zuul 如何使用zuul过滤器转换客户端请求正文? - How to transform client request body with a zuul filter? 我可以仅使用Zuul帖子过滤器获取请求的响应时间吗? - Can I get the request's response time using only a Zuul post filter? 如何在 Spring 云网关(Webflux)后过滤器中获取原始响应正文 - How to get Original response body in Spring cloud gateway (Webflux) Post filter 如何获得Volley POST响应正文? - How to get Volley POST response body? Spring 云网关 - 如何修改后过滤器中的响应正文 - Spring Cloud Gateway - How To Modify Response Body In Post Filter 如何从 Spring Boot 过滤器中的 servletResponse 获取响应正文 - How to get Response Body from servletResponse in Spring Boot Filter 我们如何在 Spring 引导过滤器中获取和设置响应主体 - How can we get and set response body in Spring Boot Filter 如何在Java中获取没有转义序列的post请求的响应主体? - How to get response body of a post request without escape sequences in Java?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM