Доступ к заголовкам ответов с помощью декоратора в Armeria
Я хотел бы добавить декоратор к моему клиенту armeria, который проверяет каждый ответ http, если был возвращен определенный заголовок http:
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()
звоню и ждет вечно. Есть ли в Армерии стандартный образец для этого? По-видимому, я не могу просто заблокировать ответ в перехватчике, но в противном случае я не смог бы найти способ получить доступ к заголовкам ответа. С помощью
subscribe
или же
toDuplicator
лучше не работало.
1 ответ
Есть два способа добиться желаемого поведения.
Первый вариант - асинхронно агрегировать ответ, а затем преобразовать его обратно в
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();
}));
});
Этот подход довольно прост и понятен, но он не работает для потокового ответа, потому что он ждет, пока не будет готово все тело ответа.
Если ваш сервис возвращает потенциально большой потоковый ответ, вы можете использовать
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