簡體   English   中英

如何在 Zuul 后置過濾器中獲取響應正文?

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

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

}

我已經設法克服了這一點。 解決方案包括 4 個步驟:

  1. ctx.getResponseDataStream()讀入 ByteArrayOutputStream
  2. 將 OutputStream 復制到 2 個 InputStreams。
  3. 將其中之一用於您的自定義目的。
  4. 使用第二個重新分配給上下文: context.setResponseBody(inputStream)
    • 從第 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);
}

感謝您的建議,這是我使用的有效代碼。

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

正如您在此示例中看到的,您有兩種方法可用於提取響應正文:

1- ctx.getResponseBody();

2- ctx.getResponseDataStream();

您必須檢查哪一個不為空並使用那個。

小心使用 filterNumber

使用大於 1000 的值會導致“InputStream 已關閉”錯誤,因為響應正文已被讀取並且

我使用了數字 10 並且工作正常

沒有一個答案對我有用。 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;
}

最簡單的解決方案是獲取一個輸入流,使用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);
//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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM