使用 Armeria 中的装饰器访问响应 headers

Accessing response headers using a decorator in Armeria

我想向我的 armeria 客户端添加一个装饰器,用于检查每个 http 响应是否返回了某个 http header:

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

但是,当启动我的客户端时,它会阻塞 join() 调用并永远等待。 Armeria 中是否有标准模式?大概我不能只阻止拦截器中的响应,但我找不到其他方法来访问响应 headers。但是,使用 subscribetoDuplicator 并没有更好的效果。

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

第一个选项是异步聚合响应,然后将其转换回 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();
    }));
});

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

如果您的服务 returns 是一个潜在的大流式响应,您可以使用 FilteredHttpResponse 过滤响应而不聚合任何内容:

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

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

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