知識庫 / Spring / Spring Cloud RSS 訂閱

Zuul 過濾器響應體修改

Spring Cloud
HongKong
5
01:03 PM · Dec 06 ,2025

1. 概述

在本教程中,我們將探討 Netflix Zuul 的後置過濾器。

Netflix Zuul 是一個位於 API 客户端和眾多微服務的邊緣服務提供者。

後置過濾器在最終響應發送到 API 客户端之前運行。這使我們有機會處理原始響應體並執行我們希望的任何操作,例如日誌記錄和其他數據轉換。

2. 依賴項

我們將要在 Spring Cloud 環境中使用 Zuul。因此,我們需要在我們的 pom.xml 的依賴管理部分添加以下內容:

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>2020.0.0</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

<dependencies>
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
        <version>2.2.2.RELEASE</version>
    </dependency>
</dependencies>

最新版本的 Spring Cloud 依賴項spring-cloud-starter-netflix-zuul 可在 Maven Central 上找到。

3. 創建一個發佈過濾

發佈過濾是一個繼承抽象類 ZuulFilter 的常規類,並且具有 post 類型的過濾:

public class ResponseLogFilter extends ZuulFilter {
    
    @Override
    public String filterType() {
        return POST_TYPE;
    }

    @Override
    public int filterOrder() {
        return 0;
    }

    @Override
    public boolean shouldFilter() {
        return true;
    }

    @Override
    public Object run() throws ZuulException {
        return null;
    }
}

請注意,我們在 filterType() 方法中返回了 POST_TYPE。 這正是將此過濾器與其他類型區分開來的關鍵。

另一個重要的方法是 shouldFilter() 方法。 我們在這裏返回 true,因為我們希望過濾器在過濾器鏈中運行。

在生產環境中,為了更好的靈活性,我們可以將此配置外部化。

讓我們更詳細地查看 run() 方法,該方法在我們的過濾器運行時會被調用。

4. 修改響應體

如前所述,Zuul 位於微服務和客户端之間。因此,它可以訪問響應體並根據需要對其進行修改後再傳遞給下游服務。

例如,我們可以讀取響應體並記錄其內容:

@Override
public Object run() throws ZuulException {

    RequestContext context = RequestContext.getCurrentContext();
    try (final InputStream responseDataStream = context.getResponseDataStream()) {

        if(responseDataStream == null) {
            logger.info("BODY: {}", "");
            return null;
        }

        String responseData = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8"));
        logger.info("BODY: {}", responseData);

        context.setResponseBody(responseData);
    }
    catch (Exception e) {
        throw new ZuulException(e, INTERNAL_SERVER_ERROR.value(), e.getMessage());
    }

    return null;
}

上面的片段展示了我們在先前創建的 ResponseLogFilterrun() 方法的完整實現。首先,我們獲取了 RequestContext 的實例。並且,通過該上下文,我們能夠使用 try-with-resources 結構獲取響應數據 InputStream

請注意,響應輸入流可能為 null,因此我們進行了檢查。這可能是由於微服務上的服務超時或其他意外異常造成的。在我們的情況下,當發生這種情況時,我們只是記錄一個空響應體。

接下來,我們將輸入流讀取到一個 String 中,以便我們可以記錄它。

非常重要的是,我們使用 context.setResponseBody(responseData) 將響應體重新添加到上下文中以進行處理。 如果省略此步驟,我們將遇到如下的 IOException: java.io.IOException: Attempted read on a closed stream.

5. 結論

綜上所述,Zuul 中的後過濾器為開發者提供了一個在將響應發送到客户端之前,對服務響應進行操作的機會。

然而,我們必須謹慎,以免意外暴露敏感信息,從而導致安全漏洞。

此外,我們應避免在後過濾器中執行耗時任務,因為這會顯著增加響應時間。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.