我正在编写Java EE servlet教程并尝试mood example。我注意到,一旦servlet调用在链中,第二次不是,就会调用doFilter两次。
我在TimeOfDayFilter.java和MoodServlet.java中添加了一些printlns来显示它。
TimeOfDayFilter.java:
...
System.out.println("TimeOfDay before"); //added
chain.doFilter(req, res);
System.out.println("TimeOfDay after"); //added
...
MoodServlet.java:
...
response.setContentType("text/html;charset=UTF-8");
System.out.println("MoodServlet"); //added
PrintWriter out = response.getWriter();
...
调用servlet时glassfish服务器(3.1)窗口的结果如下:
INFO: mood was successfully deployed in 406 milliseconds.
INFO: TimeOfDay before
INFO: MoodServlet
INFO: TimeOfDay after
INFO: TimeOfDay before
INFO: TimeOfDay after
这是预期的行为吗?如果是这样,额外通话的原因是什么?
答案 0 :(得分:4)
chain.doFilter(request,response);
这会将控件传递给与过滤器关联的servlet。 但是在执行相应的servlet之后,控件返回到上一行的末尾,然后执行当前doFilter()中的所有行。
如果要将控件永久传递给servlet而不让它返回过滤器,只需添加一个
return;
在当前过滤器中的chain.doFilter(request,response)行的末尾。
答案 1 :(得分:3)
每个请求Filter.doFilter
方法被调用一次。您可以在调用链中的其他过滤器之前以及之后(按照过滤器链中指定的顺序,按照web.xml filter-mapping
的顺序)执行一些代码,
类似于以下示例:
public MyFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException
{
codeToExecuteBeforeOtherFiltersInTheChain(request, response);
chain.doFilter(request, response);
codeToExecuteAfterOtherFiltersInTheChain(request, response);
}
}
如果您的过滤器配置为分派REQUEST
和FORWARD
请求,则对于原始请求,MyFilter.doFilter
方法将被调用一次,如果请求已经{{3} }:
使用web.xml
文件配置过滤器映射:
...
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
</filter-mapping>
...
使用forwarded注释配置过滤器映射:
@WebFilter(urlPatterns = "/*", dispatcherTypes = {
DispatcherType.REQUEST, DispatcherType.FORWARD
}) public MyFilter implements Filter {
...
}
要检查请求是否已转发,可以使用此处描述的请求属性:@WebFilter
有关过滤器的详细信息,请参见:How to know when the request is forwarded in a RequestWrapper object
答案 2 :(得分:2)
答案 3 :(得分:1)
调用过滤器两次的原因是响应创建中使用的图像,例如
out.println("<img src=\"resources/images/duke.snooze.gif\" alt=\"Duke sleeping\"/><br/>");
请参阅日志输出
2016-01-16T11:25:34.894+0100|Info: TimeOfDay doFilter method before sending to chain
2016-01-16T11:25:34.895+0100|Info: MoodServlet get method called
2016-01-16T11:25:34.895+0100|Info: TimeOfDay doFilter method after sending to chain
2016-01-16T11:25:34.942+0100|Info: TimeOfDay doFilter method before sending to chain
2016-01-16T11:25:34.942+0100|Info: TimeOfDay doFilter method after sending to chain
img标签中的@WebFilter(filterName = "TimeOfDayFilter",
urlPatterns = {"/*"},
initParams = {
@WebInitParam(name = "mood", value = "awake")})
它将拦截进入心情应用程序的所有请求。练习只是尝试从响应中删除图像或更改网址模式以仅拦截最终在MoodServlet中的请求
@WebFilter(filterName = "TimeOfDayFilter",
urlPatterns = {"/report"},
initParams = {
@WebInitParam(name = "mood", value = "awake")})
两者都会导致一次调用doFilter,就像你原先预期的那样
2016-01-16T11:28:53.485+0100|Info: TimeOfDay doFilter method before sending to chain
2016-01-16T11:28:53.486+0100|Info: MoodServlet get method called
2016-01-16T11:28:53.487+0100|Info: TimeOfDay doFilter method after sending to chain
答案 4 :(得分:0)
当doFilter
被调用两次(或多次)时,我遇到了相同的问题。问题是过滤器处理每个请求,包括css,js,image和所有其他文件,而我希望每个页面有一个请求,因此我通过添加以下代码解决了该问题:
@WebFilter(filterName = "MyCustomFilter")
public class MyCustomFilter implements Filter {
public void doFilter(ServletRequest request,ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
String accept = httpRequest.getHeader("accept");
// Since the filter handles every request
// we have to ensure that the request is asking for text/html
if (accept == null || !accept.toLowerCase().startsWith("text/html")) {
chain.doFilter(request, response);
return;
}
// your code goes here
希望这会帮助像我这样搜索过此问题的人。
答案 5 :(得分:0)
正如Mohan所说,如果您已经在Application类中注册了@Component,它将使您的过滤器被调用两次,
resources.add(new MyFilter());
如果是这种情况,则必须在注释或注册之间进行选择。但这仅对使用Spring的JAX-RS应用程序有效。不是这个问题的话题。
答案 6 :(得分:0)
正如@BalusC所说,在我的情况下,默认情况下浏览器正在请求favicon.ico,因此浏览器的控制台出现错误
Failed to load resource: the server responded with a status of 404 (Not Found)
所以我遵循了this answer并且错误消失了,但是随后我得到了两次被调用的过滤器。
我的解决方案
我替换了
<link rel="shortcut icon" href="#" />
为此:
<link rel="shortcut icon" href="../assets/img/valid_icon.png" />
答案 7 :(得分:-1)
在CustomFilter类中删除@Component之后,我解决了相同的问题。