Можно ли исключить некоторые конкретные URL-адреса из <url-pattern> внутри <filter-mapping>?
Я хочу, чтобы какой-то конкретный фильтр применялся для всех URL-адресов, кроме одного конкретного (т.е. для /*
, за исключением /specialpath
).
Есть ли возможность сделать это?
пример кода:
<filter>
<filter-name>SomeFilter</filter-name>
<filter-class>org.somproject.AFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>SomeFilter</filter-name>
<url-pattern>/*</url-pattern> <!-- the question is: how to modify this line? -->
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
Ответы
Ответ 1
Стандартный API Servlet не поддерживает этот объект. Возможно, вам понадобится использовать фильтр перезаписи URL-адреса для этого, например Tuckey one (который очень похож на Apache HTTPD mod_rewrite
), или добавить проверьте метод doFilter()
фильтра, прослушивающего /*
.
String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
chain.doFilter(request, response); // Just continue chain.
} else {
// Do your business stuff here for all paths other than /specialpath.
}
При необходимости вы можете указать пути, которые будут проигнорированы как init-param
фильтра, чтобы вы могли управлять им в web.xml
в любом случае. Вы можете получить его в фильтре следующим образом:
private String pathToBeIgnored;
public void init(FilterConfig config) {
pathToBeIgnored = config.getInitParameter("pathToBeIgnored");
}
Если фильтр является частью стороннего API и, следовательно, вы не можете его изменить, сопоставьте его с более конкретным url-pattern
, например. /otherfilterpath/*
и создайте новый фильтр на /*
, который перейдет к пути, соответствующему стороннему фильтру.
String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
chain.doFilter(request, response); // Just continue chain.
} else {
request.getRequestDispatcher("/otherfilterpath" + path).forward(request, response);
}
Чтобы этот фильтр не вызывал себя в бесконечном цикле, вы должны позволить ему прослушивать (отправлять) только на REQUEST
, а сторонний фильтр - на FORWARD
.
См. также:
Ответ 2
Я использовал подход описанный Эриком Догерти: Я создал специальный сервлет, который всегда отвечает кодом 403 и ставит его отображение перед общим один.
Отображение фрагмента:
<servlet>
<servlet-name>generalServlet</servlet-name>
<servlet-class>project.servlet.GeneralServlet</servlet-class>
</servlet>
<servlet>
<servlet-name>specialServlet</servlet-name>
<servlet-class>project.servlet.SpecialServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>specialServlet</servlet-name>
<url-pattern>/resources/restricted/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>generalServlet</servlet-name>
<url-pattern>/resources/*</url-pattern>
</servlet-mapping>
И класс сервлета:
public class SpecialServlet extends HttpServlet {
public SpecialServlet() {
super();
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
response.sendError(HttpServletResponse.SC_FORBIDDEN);
}
}
Ответ 3
Этот подход работает, когда вы хотите предотвратить определенный фильтр и все следующие. Он должен хорошо работать, если вы, например. хотите обслуживать некоторый контент как статические ресурсы в вашем контейнере сервлетов, а не позволять логике вашего приложения (через фильтр, такой как GuiceFilter):
Сопоставьте папку с вашими статическими файлами ресурсов на сервлет по умолчанию. Создайте фильтр сервлета и поместите его перед GuiceFilter в ваш web.xml. В созданном вами фильтре вы можете разделить между отправкой некоторых запросов в GuiceFilter и другими непосредственно на диспетчера. Пример следует...
web.xml
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>/static/*</url-pattern>
</servlet-mapping>
<filter>
<filter-name>StaticResourceFilter</filter-name>
<filter-class>com.project.filter.StaticResourceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>StaticResourceFilter</filter-name>
<url-pattern>/static/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
StaticResourceFilter.class
public class StaticResourceFilter implements Filter {
private final static Logger LOGGER = LoggerFactory.getLogger(StaticResourceFilter.class);
private static final String RESOURCE_PATH = "/static/";
@Override
public void init(final FilterConfig filterConfig) throws ServletException {
LOGGER.info("StaticResourceFilter initialized");
}
@Override
public void doFilter(final ServletRequest request, final ServletResponse response,
final FilterChain chain) throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
if (path.toLowerCase().startsWith(RESOURCE_PATH)) {
request.getRequestDispatcher(path).forward(request, response);
} else {
chain.doFilter(request, response);
}
}
@Override
public void destroy() {
LOGGER.info("StaticResourceFilter destroyed");
}
}
К сожалению, если вы просто хотите пропустить один шаг в цепочке фильтров, сохраняя при этом следующие значения, это не сработает.
Ответ 4
Я не думаю, что вы можете, единственная альтернатива конфигурации - перечислить пути, которые вы хотите отфильтровать, поэтому вместо /*
вы можете добавить некоторые для /this/*
и /that/*
и т.д., но это не приведет к достаточному решению, если у вас есть много путей.
Что вы можете сделать, так это добавить параметр в фильтр, предоставляющий выражение (например, регулярное выражение), которое используется для пропуска функции фильтра для согласованных путей.
Контейнер сервлета по-прежнему будет вызывать ваш фильтр для этого URL-адреса, но вам лучше контролировать конфигурацию.
Edit
Теперь, когда вы упоминаете, что у вас нет контроля над фильтром, то, что вы можете сделать, либо наследуется от этого фильтра, вызывающего методы super
в его методах, за исключением случаев, когда URL-адрес, который вы хотите пропустить, присутствует и следует за цепочкой фильтров, например @BalusC предложил или создал фильтр, который создает экземпляр вашего фильтра и делегатов при тех же обстоятельствах. В обоих случаях параметры фильтра будут включать как добавляемый параметр выражения, так и параметры фильтра, на который вы наследуете или делегируете.
Преимущество создания фильтра делегирования (обертки) заключается в том, что вы можете добавить класс фильтра обернутого фильтра в качестве параметра и повторно использовать его в других ситуациях, подобных этому.
Ответ 5
Мне также пришлось фильтровать на основе шаблона URL (/{servicename}/api/stats/) в Java-коде.
if (path.startsWith("/{servicename}/api/statistics/")) {
validatingAuthToken(((HttpServletRequest) request).getHeader("auth_token"));
filterChain.doFilter(request, response);
}
Но его причудливый, этот сервлет не поддерживает шаблон url, отличный от (/*). Это должно быть очень распространенным случаем для API сервлета!
Ответ 6
Я столкнулся с одной и той же проблемой, но я нашел андерсера, показанного ниже.
web.xml
<!-- set this param value for the filter-->
<init-param>
<param-name>freePages</param-name>
<param-value>
MainFrame.jsp;
</param-value>
</init-param>
filter.java
strFreePages = config.getInitParameter("freePages"); //get the exclue pattern from config file
isFreePage(strRequestPage) //decide the exclude path
Таким образом, вам не нужно беспокоить конкретный класс фильтра.