首页 > 解决方案 > Accessing response headers using a decorator in Armeria

问题描述

I would like to add a decorator to my armeria client that checks each http response if a certain http header was returned:

    builder.decorator((delegate, ctx, req) -> {
      final HttpResponse response = delegate.execute(ctx, req);
      final AggregatedHttpResponse r = response.aggregate().join();
      for (Map.Entry<AsciiString, String> header : r.headers()) {
        if ("warning".equalsIgnoreCase(header.getKey().toString())) {
          throw new IllegalArgumentException("Detected usage of deprecated API for request "
            + req.toString() + ":\n" + header.getValue());
        }
      }
      return response;
    });

However, when starting my client it blocks on the join() call and waits forever. Is there a standard pattern for this in Armeria ? Presumably i cannot just block on the response in an interceptor, but i could not find a way to access the response headers otherwise. Using subscribe or toDuplicator did not work any better though.

标签: armeria

解决方案


有两种方法可以实现所需的行为。

第一个选项是异步聚合响应,然后将其转换回HttpResponse. 关键 API 是AggregatedHttpResponse.toHttpResponse()HttpResponse.from(CompletionStage)

builder.decorator(delegate, ctx, req) -> {
    final HttpResponse res = delegate.serve(ctx, req);
    return HttpResponse.from(res.aggregate().thenApply(r -> {
        final ResponseHeaders headers = r.headers();
        if (headers...) {
            throw new IllegalArgumentException();
        }
        // Convert AggregatedHttpResponse back to HttpResponse.
        return r.toHttpResponse();
    }));
});

这种方法相当简单直接,但它不适用于流式响应,因为它会等到完整的响应主体准备好。

如果您的服务返回可能很大的流式响应,您可以使用 aFilteredHttpResponse过滤响应而不聚合任何内容:

builder.decorator(delegate, ctx, req) -> {
    final HttpResponse res = delegate.serve(ctx, req);
    return new FilteredHttpResponse(res) {
        @Override
        public HttpObject filter(HttpObject obj) {
            // Ignore other objects like HttpData.
            if (!(obj instanceof ResponseHeaders)) {
                return obj;
            }

            final ResponseHeaders headers = (ResponseHeaders) obj;
            if (headers...) {
                throw new IllegalArgumentException();
            }

            return obj;
        }
    };
});

它比第一个选项稍微冗长,但它不会在内存中缓冲响应,这对于大型流式响应非常有用。

理想情况下,将来我们希望在HttpResponseor中添加更多运算符StreamMessage。请继续关注此问题页面并添加任何关于更好 API 的建议:https ://github.com/line/armeria/issues/3097


推荐阅读