51

我正在尝试使用 SpringMVC 编写一个 Web 应用程序。通常我只是将一些虚构的文件扩展名映射到 Spring 的前端控制器并愉快地生活,但这次我将使用类似 REST 的 URL,没有文件扩展名。

将我的上下文路径下的所有内容映射到前端控制器(我们称之为“应用程序”)意味着我也应该处理静态文件,这是我宁愿不做的事情(为什么要重新发明另一个轮子?),所以与 tomcat 的默认值进行一些组合servlet(我们称之为“ tomcat ”)似乎是要走的路。

我得到了工作做类似的事情

<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>*.ext</url-pattern>
</servlet-mapping>

并为我的静态内容的每个文件扩展名重复后者。我只是想知道为什么以下设置(对我来说与上面的设置相同)不起作用。

<!-- failed attempt #1 -->
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/*</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>*.ext</url-pattern>
</servlet-mapping>

<!-- failed attempt #2 -->
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>tomcat</servlet-name>
  <url-pattern>/some-static-content-folder/*</url-pattern>
</servlet-mapping>

任何人都可以解释一下吗?

4

3 回答 3

43

我想我可能知道发生了什么事。

在您的工作 web.xml 中,您已将您的 servlet 设置为默认 servlet(如果没有其他匹配项,/ 本身就是调用的默认 servlet),它将响应与另一个映射不匹配的任何请求。

在 Failed 1 中,您的 /* 映射确实是有效的路径映射。使用 web.xml 中的 /* 映射,它会回答除其他路径映射之外的所有请求。根据规范,扩展映射是被显式映射覆盖的隐式映射。这就是扩展映射失败的原因。一切都明确映射到应用程序。

在 Failed 2 中,App 负责一切,除了与静态内容映射匹配的内容。为了显示我设置的快速测试中发生了什么。这是一个例子。 /some-static-content-folder/包含test.png

试图访问 test.png 我试过:

/some-static-content-folder/test.png

并且找不到该文件。然而尝试

/some-static-content-folder/some-static-content-folder/test.png

它出现了。因此,似乎 Tomcat 默认 servlet(至少 6.0.16)丢弃了 servlet 映射,并将尝试使用剩余路径查找文件。根据这篇文章Servlet for serving static content Jetty 提供了您和我所期望的行为。

有什么原因你不能为你的休息电话做一些事情,比如映射一个根目录。像 app 映射到 /rest_root/* 之类的东西比您负责 rest_root 文件夹中发生的任何事情,但其他任何地方都应由 Tomcat 处理,除非您进行另一个显式映射。我建议将您的 rest servlet 设置为路径映射,因为它可以更好地声明意图。使用 / 或 /* 似乎不合适,因为您必须列出例外情况。以 SO 为例,我的其余映射将类似于

/users/* 用于用户 servlet

/posts/* 用于帖子 servlet

映射顺序

  1. 显式(路径映射)
  2. 隐式(扩展映射)
  3. 默认 (/)

请纠正我做错的任何事情。

于 2008-10-28T22:36:29.960 回答
3

作为参考,“失败的尝试 #2”在 Tomcat >= 到 6.0.29 的版本中完全正确。

这是在 6.0.29 版中修复的 Tomcat 错误的结果:

https://issues.apache.org/bugzilla/show_bug.cgi?id=50026

<!-- Correct for Tomcat >= 6.0.29 or other Servlet containers -->
<servlet-mapping>
  <servlet-name>app</servlet-name>
  <url-pattern>/</url-pattern>
</servlet-mapping>

<servlet-mapping>
  <servlet-name>default</servlet-name>
  <url-pattern>/some-static-content-folder/*</url-pattern>
</servlet-mapping>
于 2014-10-31T09:01:59.863 回答
2

我从未尝试过像这样映射 servlet,但我认为/* 在技术上确实以 / 开头和以 /* 结尾,即使两个匹配项使用了相同的字符。

于 2008-10-28T20:32:52.457 回答