don*_*ior 3 mapping servlets infinite-loop
我想将我的 servlet 映射到/*,但它因无限循环而失败。
<servlet>
<servlet-name>helloServlet</servlet-name>
<servlet-class>my.HelloServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>helloServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
Run Code Online (Sandbox Code Playgroud)
Java代码是:
public class HelloServlet extends HttpServlet {
public void doGet(HttpServletRequest request, HttpServletResponse response){
request.getRequestDispatcher("/WEB-INF/jsps/hello.jsp").forward(request, response);
}
}
Run Code Online (Sandbox Code Playgroud)
如果我映射到/hello,一切正常。
当HelloServlet映射到 时/*,它也会被调用RequestDispatcher#forward()并导致无限循环。
这是怎么引起的,我该如何解决?
这不可能。JSP 实际上应该调用容器的 builtin JspServlet。但是/*webapp定义的映射有更高的优先级。
您需要将 servlet 映射到更具体的 URL 模式,例如/pages/*创建一个 servlet 过滤器,将非静态请求转发到该 servlet。是的,非静态请求(图像/CSS/JS 文件)也包含在 中/*,但它们根本不应由 servlet 处理。
假设您在/resources文件夹中拥有所有静态资源,则应执行以下操作:
<filter>
<filter-name>filter</filter-name>
<filter-class>com.example.Filter</filter-class>
</filter>
<filter-mapping>
<filter-name>filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>controller</servlet-name>
<servlet-class>com.example.Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>controller</servlet-name>
<url-pattern>/pages/*</url-pattern>
</servlet-mapping>
Run Code Online (Sandbox Code Playgroud)
在过滤器中具有以下内容doFilter():
HttpServletRequest req = (HttpServletRequest) request;
String path = req.getRequestURI().substring(req.getContextPath().length());
if (path.startsWith("/resources")) {
chain.doFilter(request, response); // Goes to container's own default servlet.
} else {
request.getRequestDispatcher("/pages" + uri).forward(request, response); // Goes to controller servlet.
}
Run Code Online (Sandbox Code Playgroud)
这完全透明地发生,/pagesURL没有任何更改。转发到 JSP 不会触发过滤器或 servlet。默认情况下,过滤器不会启动转发,并且 JSP 转发路径不再与控制器 servlet 的 URL 模式匹配。
或者,如果您有自己的默认 servlet 实现,那么您可以将 servlet 映射到/并让它委托给默认 servlet,如果请求不适用于前端控制器请求。这就是 Spring MVC 在幕后所做的事情。然而,创建默认 servlet 并不是一项简单的任务,因为它应该能够响应条件请求、缓存请求、流请求、恢复请求、目录列表请求等。