web.xml中的Servlet url映射是如何使用的?

25

我有一个包含以下内容的 web.xml 文件:

<servlet>
    <servlet-name>servlet1</servlet-name>
    <servlet-class>org.mycompany.test1</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet2</servlet-name>
    <servlet-class>org.mycompany.test2</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>servlet1</servlet-name>
    <url-pattern>/path/test</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet2</servlet-name>
    <url-pattern>/path/test/*</url-pattern>
</servlet-mapping>

我尝试了 requests

.../path/test/abc 
.../path/test

为什么这两个请求都由Servlet2处理?

更新

谢谢大家的帮助。 我意识到这取决于servlet-mapping声明的顺序。 我尝试了这个web.xml。

<servlet>
    <servlet-name>servlet1</servlet-name>
    <servlet-class>org.mycompany.test1</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet2</servlet-name>
    <servlet-class>org.mycompany.test2</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet3</servlet-name>
    <servlet-class>org.mycompany.test3</servlet-class>
</servlet>
<servlet>
    <servlet-name>servlet4</servlet-name>
    <servlet-class>org.mycompany.test4</servlet-class>
</servlet>

<servlet-mapping>
    <servlet-name>servlet1</servlet-name>
    <url-pattern>/path/test</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet2</servlet-name>
    <url-pattern>/path/test/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet3</servlet-name>
    <url-pattern>/path/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
    <servlet-name>servlet4</servlet-name>
    <url-pattern>/path</url-pattern>
</servlet-mapping>

结果:

.../path/test/abc - servlet2
.../path/test/ - servlet2
.../path/test - servlet2

.../path/abc - servlet3
.../path/ - servlet4
.../path - servlet4

也许你没有运行当前版本的网络应用程序。你使用任何集成开发环境吗?你是如何部署的? - Uooo
2
/path/test符合/path/test/*规则,它们冲突了。 - Alexandre Lavoie
1
@AurA 鉴于它是XML,注释肯定不会用/* - benzonico
1
@MagnusTengdahl 我已经修复了语法高亮 - 你可以通过在代码块前面加上 <!-- language: lang-xml -->(或 lang-java 或其他)来强制将代码块视为特定的语言。 - Ian Roberts
6
@wfr - 你能否编辑你的问题,删除或澄清UPDATE部分。你在那里说的不正确。映射的顺序是无关紧要的。我花了很多时间假设你的UPDATE是解决你的问题的方法。也许它确实是,但只是偶然发生的。谢谢。 - BxlSofty
显示剩余4条评论
2个回答

52
从Servlet 3.0 specification开始,这就是Web容器在接收到请求后必须定位Servlet的方式(重点在我):

用于映射到servlet的路径是请求对象中的请求URL减去上下文路径和路径参数。以下是使用的URL路径映射规则,按顺序使用第一个成功匹配将被使用,不会尝试进一步匹配

  1. 容器将尝试查找请求路径与servlet路径的精确匹配。成功匹配选择servlet。
  2. 容器将递归尝试匹配最长路径前缀。这是通过每次沿着路径树向下移动一个目录来完成的,使用“/”字符作为路径分隔符。最长匹配确定选择的servlet。
  3. 如果URL路径中的最后一段包含扩展名(例如.jsp),则servlet容器将尝试匹配处理扩展名请求的servlet。扩展名定义为最后一个“.”字符之后的部分。
  4. 如果前面三条规则都没有导致servlet匹配,则容器将尝试提供适合所请求资源的内容。如果应用程序定义了“默认”servlet,则将使用它。许多容器提供用于提供内容的隐式默认servlet。

容器必须对匹配使用区分大小写的字符串比较。

你还应该查看映射的规范(如下所示):
在Web应用程序部署描述符中,以下语法用于定义映射:
- 以“/”字符开头并以“/*”后缀结尾的字符串用于路径映射。 - 以“*.”前缀开头的字符串用作扩展名映射。 - 空字符串("")是一个特殊的URL模式,完全映射到应用程序的上下文根,即形式为“http://host:port//”的请求。在这种情况下,路径信息是“/”,servlet路径和上下文路径为空字符串("")。 - 仅包含“/”字符的字符串表示应用程序的“默认”servlet。在这种情况下,servlet路径是请求URI减去上下文路径,路径信息为空。 - 所有其他字符串仅用于精确匹配。
让我们现在看一些示例。考虑以下映射集:
路径模式 Servlet /foo/bar/* servlet1 /baz/* servlet2 /catalog servlet3 *.bop servlet4
将会产生以下行为:
传入路径 Servlet 处理请求 /foo/bar/index.html servlet1 /foo/bar/index.bop servlet1 /baz servlet2 /baz/index.html servlet2 /catalog servlet3 /catalog/index.html “default” servlet /catalog/racecar.bop servlet4 /index.bop servlet4
请注意,在/catalog/index.html和/catalog/racecar.bop的情况下,与“/catalog”映射的servlet没有使用,因为匹配不是精确的。
现在来谈谈你的问题 :)
/path/test属于映射规范的第5点。这意味着仅以/path/test结尾的路径将针对servlet1。
但是,/path/test/*符合同一规范的第一点。这意味着:

.../path/test将由servlet1处理,

.../path/test/abc将由servlet2处理。

这在我的测试应用程序中得到了验证。


3
为什么你接受了这个回复作为答案?它似乎不同意你观察到servlet2处理了 /path/test。 - eel ghEEz
谢谢。您解决了我的问题,这里是链接:http://stackoverflow.com/questions/33522888/how-does-the-getservletmapping-affects-the-url-in-spring-webmvc - smwikipedia

1

你的路径冲突。

你们两个的路径意思相同,'/*'没有任何区别。 很明显,当你尝试你的路径时,最后一次匹配(servlet2)被执行。

通常你会用Servlet名称来设置路径,例如:

/path/test/servlet1
/path/test/servlet2

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接