使用 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。但是,使用 subscribe
或 toDuplicator
并没有更好的效果。
有两种方法可以实现所需的行为。
第一个选项是异步聚合响应,然后将其转换回 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;
}
};
});
它比第一个选项稍微冗长,但它不会在内存中缓冲响应,这对于大型流式响应非常有用。
理想情况下,将来我们希望向 HttpResponse
或 StreamMessage
添加更多运算符。请继续关注此问题页面并添加任何更好的建议API:https://github.com/line/armeria/issues/3097
我想向我的 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。但是,使用 subscribe
或 toDuplicator
并没有更好的效果。
有两种方法可以实现所需的行为。
第一个选项是异步聚合响应,然后将其转换回 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;
}
};
});
它比第一个选项稍微冗长,但它不会在内存中缓冲响应,这对于大型流式响应非常有用。
理想情况下,将来我们希望向 HttpResponse
或 StreamMessage
添加更多运算符。请继续关注此问题页面并添加任何更好的建议API:https://github.com/line/armeria/issues/3097