1. Обзор
Большинство веб-приложений используют такие операции, как ведение журнала запросов, проверка подлинности или аутентификация. И, более того, такие задачи обычно разделяются между набором конечных точек HTTP .
Хорошей новостью является то, что веб-фреймворк Spring предоставляет механизм фильтрации именно для этой цели.
В этом уроке мы узнаем, как задача в стиле фильтра может быть включена или исключена из выполнения для заданного набора URL-адресов .
2. Фильтр для определенных URL-адресов
Допустим, наше веб-приложение должно регистрировать некоторую информацию о своих запросах, такую как их пути и типы контента. Один из способов сделать это-создать фильтр ведения журнала.
2.1. Фильтр регистрации
Во-первых, давайте создадим наш loggingfilter в классе Log Filter , который расширяет класс | OncePerRequestFilter и реализует метод doFilterInternal :
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String path = request.getRequestURI(); String contentType = request.getContentType(); logger.info("Request URL path : {}, Request content type: {}", path, contentType); filterChain.doFilter(request, response); }
2.1. Фильтр правил
Предположим, что нам нужно, чтобы задача ведения журнала выполнялась только для выбранных шаблонов URL-адресов, а именно /health , /faq/*. Для этого мы зарегистрируем наш фильтр ведения журнала с помощью FilterRegistrationBean таким образом, чтобы он соответствовал только требуемым шаблонам URL-адресов:
@Bean public FilterRegistrationBeanlogFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new LogFilter()); registrationBean.addUrlPatterns("/health","/faq/*"); return registrationBean; }
2.2. Фильтр исключения
Если мы хотим исключить URL-адреса из выполнения задачи ведения журнала, мы можем легко добиться этого двумя способами:
- Для нового URL-адреса убедитесь, что он не соответствует шаблонам URL-адресов, используемым фильтром
- Для старого URL-адреса, для которого ранее было включено ведение журнала, мы можем изменить шаблон URL-адреса, чтобы исключить этот URL-адрес
3. Фильтр для всех возможных URL-адресов
Мы легко выполнили наш предыдущий вариант использования включения URL-адресов в фильтр Log с минимальными усилиями. Однако становится сложнее, если Фильтр использует подстановочный знак (*) для сопоставления всех возможных URL-шаблонов.
В этом случае нам нужно будет самостоятельно написать логику включения и исключения.
3.1. Пользовательский фильтр
Клиенты могут отправлять полезную информацию на сервер с помощью заголовков запросов. Допустим, ваше веб-приложение в настоящее время работает только в Соединенных Штатах, а это означает, что мы не хотим обрабатывать запросы, поступающие из других стран.
Давайте далее представим, что наше веб-приложение указывает локаль с помощью заголовка запроса X-Country-Code . Следовательно, каждый запрос поставляется с этой информацией, и у нас есть четкий аргумент в пользу использования фильтра.
Давайте реализуем Фильтр , который проверяет заголовок, отклоняя запросы, которые не соответствуют нашим условиям:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String countryCode = request.getHeader("X-Country-Code"); if (!"US".equals(countryCode)) { response.sendError(HttpStatus.BAD_REQUEST.value(), "Invalid Locale"); return; } filterChain.doFilter(request, response); }
3.2. Регистрация фильтра
Начнем с того, что l et использует подстановочный знак звездочка (*) для регистрации нашего фильтра , чтобы соответствовать всем возможным URL-шаблонам:
@Bean public FilterRegistrationBeanheaderValidatorFilter() { FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new HeaderValidatorFilter()); registrationBean.addUrlPatterns("*"); return registrationBean; }
В более поздний момент времени мы можем исключить шаблоны URL-адресов, которые не требуются для выполнения задачи проверки информации заголовка запроса локали.
4. Исключение URL-адресов
В этом разделе мы узнаем, как исключить URL-адреса для нашего клиента Filter .
4.1. Наивная стратегия
Давайте еще раз представим, что у нас есть веб-маршрут в /health , который можно использовать для проверки работоспособности приложения для пинг-понга.
До сих пор все запросы запускали наш фильтр. Как мы можем догадаться, это накладные расходы, когда речь заходит о нашей проверке здоровья.
Итак, давайте упростим наши запросы /здоровье , исключив их из основной части нашего фильтра:
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String path = request.getRequestURI(); if ("/health".equals(path)) { filterChain.doFilter(request, response); return; } String countryCode = request.getHeader("X-Country-Code"); // ... same as before }
Мы должны отметить, что добавление этой пользовательской логики в метод doFilter вводит связь между конечной точкой /health и нашим фильтром . Таким образом, это не оптимально, так как мы можем нарушить логику фильтрации, если изменим конечную точку проверки работоспособности без внесения соответствующих изменений в метод doFilter .
4.2. Использование метода “Не следует фильтровать”
В предыдущем подходе мы ввели тесную связь между исключением URL-адреса и логикой выполнения задачи для фильтра. Можно непреднамеренно ввести ошибку в одну часть, намереваясь внести изменения в другую часть.
Вместо этого мы можем изолировать два набора логики, переопределив метод Не должен фильтровать :
@Override protected boolean shouldNotFilter(HttpServletRequest request) throws ServletException { String path = request.getRequestURI(); return "/health".equals(path); }
В результате метод do Internal Filter() соблюдает принцип единой ответственности :
@Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String countryCode = request.getHeader("X-Country-Code"); // ... same as before }
5. Заключение
В этом руководстве мы изучили, как исключить шаблон(ы) URL-адресов из фильтра сервлетов в веб-приложении Spring Boot для двух вариантов использования, а именно ведения журнала и проверки заголовка запроса.
Более того, мы узнали, что становится сложно исключить определенный набор URL-адресов для фильтра, который использует подстановочный знак * для сопоставления всех возможных шаблонов URL-адресов .
Как всегда, полный исходный код учебника доступен на GitHub .