1. 概要

このチュートリアルでは、NetflixZuulの投稿フィルターを見ていきます。

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の最新バージョンはMavenCentralにあります。

3. 投稿フィルターの作成

postフィルターは、抽象クラス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を返したことに注意してください。 これが、このフィルターを他のタイプと実際に区別するものです。

注意すべきもう1つの重要なメソッドは、 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のインスタンスを取得しました。 そして、そのコンテキストから、リソース構成を試して応答データInputStreamを取得することができました。

応答入力ストリームはnull、である可能性があることに注意してください。これが、それをチェックする理由です。 これは、サービスのタイムアウトまたはマイクロサービス上のその他の予期しない例外が原因である可能性があります。 この場合、これが発生したときに空の応答本文をログに記録するだけです。

今後は、入力ストリームを String に読み込み、ログに記録できるようにします。

非常に重要なのは、context.setResponseBody(responseData)を使用して処理するために、応答本文をコンテキストに追加することです。 この手順を省略すると、 IOException 次の線に沿って: java .io.IOException:閉じたストリームで読み取りを試みました

5. 結論

結論として、Zuulの投稿フィルターは、開発者がサービス応答をクライアントに送信する前に何かを行う機会を提供します。

ただし、機密情報を誤って公開しないように注意する必要があります。これにより、侵害が発生する可能性があります。

さらに、ポストフィルター内で長時間実行されるタスクを実行すると、応答時間が大幅に長くなる可能性があるため、注意が必要です。

いつものように、ソースコードはGitHubから入手できます。