Каков наилучший (или наиболее эффективный способ) реализации управления несчастными путями с помощью фильтров SCG и ответа с телом? Обработка исключений или перезапись ответов?
Сценарий
Мы реализуем шлюз API с некоторыми сложными фильтрами GatewayFilter (между различными типами регулирования и некоторыми другими поведениями), которые имеют общий несчастный путь, где они заканчиваются обработка цепочки обмена и должна немедленно вернуть ответ 4xx с указанным c общим форматом тела (json / xml на основе заголовка Accept, у нас есть устаревшие требования совместимости).
Первоначальное решение
Первоначально я решил использовать фильтр, а затем попытаться написать ответ с одним из этих параметров:
response.setStatusCode(..);
//set headers
return response.writeAndFlushWith(...);
или
response.setStatusCode(..);
//set headers
return response.writeWith(...);
или даже
response.setStatusCode(..);
exchange.mutate().response(...);
return response.setComplete();
в каждом указанном c фильтре. Но обработка ответа тела кажется довольно многословным процессом, плюс форматирование ошибки, обеспечиваемое фильтром, не должно беспокоить специфицированный c фильтр. Мы хотим разделения интересов, поэтому фильтр должен определять заголовки, статус и сообщение об ошибке, но кто-то другой должен преобразовать это в надлежащий формат ответа.
Так что после долгого (и кровавого :)) обсуждения мы пришли с двумя возможными вариантами. Давайте предположим, что у нас есть 4 фильтра, и наш счастливый путь был бы (с некоторым приближением без учета наложения из глобального порядка фильтров):
(initial global filters) -> 1 -> 2 -> 3 -> 4-> 5 -> (other global filters) -> Routing -> (other global filters) -> 5 -> 4-> 3 -> 2 -> 1 -> 0 -> (initial global filters) -> Response
Вариант 1 - Обработка ошибок
Реализуйте класс java MyErrorHandler extends DefaultErrorWebExceptionHandler
и java MyErrorAttributes extends DefaultErrorAttributes
, и это делает волхвы c.
Это означает, что в фильтре Speci c выдается исключение, которое расширяет ResponseStatusException
или аннотируется @ResponseStatus
и направить его в ExceptionHandler. Это имеет преимущество в том, что прерывает всю обработку обмена в фильтрах, если я не ошибаюсь. Например: учитывая 3 фильтра и фильтр 3, создающий исключение, мы имеем ... 1 -> 2 -> 3 -> ExH -> (other global filters) -> Response
Вариант 2 - Запись ответа
Добавить фильтр (фильтр 0) в верхнюю позицию, возможно, один расширяющийся ModifyResponseGatewayFilter
который управляет ошибками записи в ответе, просматривая специфицированный c атрибут обмена (например: gateway.error
) для bean-компонента и записывает ответ, и имеет фильтр в цепочке, задающий c bean и сгенерируйте ответ с этим.
Это будет иметь следующий поток: ... -> 0 -> 1 -> 2 -> 3 -> 2 -> 1 -> 0 -> (other global filters) -> Response
Проблемы
Опция
- Опция 1 кажется опцией короткого замыкания, которая действительно блокирует обработку и основывается на существующих возможностях (ExceptionHandler), но мне говорят, что исключения являются ужасным бременем для эффективности, так как они вынуждены строить всю трассировку стека
- Вариант 2, кажется, более эффективный, но тогда ответ пузырится через все «постовые» фильтры, и мы должны убедиться, что никакой другой фильтр не пытается обновить ответ, проверяя специфицируемый c атрибут обмена (например:
gateway.error
)
RedisRateLimiter, предлагаемый SCG, использует option2, но не переписывает тело и использует response.setComplete()
, но это не ' Позволяет переписывать любое тело позже.
Является ли это предпочтительным подходом?