HttpServletRequest中的getRequestURI方法和getPathInfo方法有什么区别?

173
我正在制作一个简单、非常轻量级的前端控制器。为了选择正确的处理程序(操作),我需要将请求路径与不同的处理程序匹配。
在我的本地机器上,HttpServletRequest.getPathInfo()HttpServletRequest.getRequestURI()返回相同的结果。但我不确定它们在生产环境中会返回什么。
那么,这些方法有什么区别,我应该选择哪个?

2
你也许会发现这个答案很有用。 - BalusC
@BalusC:谢谢,我已经在使用那个答案中的一些提示了。 - Roman
这篇文章通过一个漂亮的图表解释了不同之处:https://agiletribe.wordpress.com/2016/02/23/httpservletrequest-path-decoding/ - AgilePro
4个回答

552

我将在此处放置一个小的比较表格(只是为了有个地方):

Servlet被映射为/test%3F/*,应用程序部署在/app下。

http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=S%3F+ID?p+1=c+d&p+2=e+f#a

Method              URL-Decoded Result           
----------------------------------------------------
getContextPath()        no      /app
getLocalAddr()                  127.0.0.1
getLocalName()                  30thh.loc
getLocalPort()                  8480
getMethod()                     GET
getPathInfo()           yes     /a?+b
getProtocol()                   HTTP/1.1
getQueryString()        no      p+1=c+d&p+2=e+f
getRequestedSessionId() no      S%3F+ID
getRequestURI()         no      /app/test%3F/a%3F+b;jsessionid=S+ID
getRequestURL()         no      http://30thh.loc:8480/app/test%3F/a%3F+b;jsessionid=S+ID
getScheme()                     http
getServerName()                 30thh.loc
getServerPort()                 8480
getServletPath()        yes     /test?
getParameterNames()     yes     [p 2, p 1]
getParameter("p 1")     yes     c d

在上面的示例中,服务器运行在 localhost:8480 上,名称 30thh.loc 被放置在操作系统的 hosts 文件中。

注释

  • "+" 仅在查询字符串中处理为空格。

  • 锚点 "#a" 不会传输到服务器。只有浏览器可以使用它。

  • 如果servlet映射中的 url-pattern 不以 * 结尾(例如 /test*.jsp),则 getPathInfo() 返回 null

如果使用Spring MVC

  • 方法 getPathInfo() 返回 null

  • 方法 getServletPath() 返回上下文路径和会话ID之间的部分。在上面的示例中,值将是 /test?/a?+b

  • 小心使用Spring中的@RequestMapping@RequestParam的URL编码部分。它有漏洞(当前版本为3.2.4),通常不能按预期工作


31
我正在将你的回答打印出来,并将其制作成海报张贴在我们的办公室。这就是它有多么有用! - Ibrahim Arief
2
如果servlet映射中的url-pattern不以结尾(例如/test或.jsp),则getPathInfo()返回null。太棒了。 - Boris Treukhov
1
我认为getRequestURI()getRequestURL()都应该返回未解码的jsessionid,即在这种情况下是S%3F+ID。至少在Tomcat/8.5.6上是这样的。 - Gediminas Rimsa

83

getPathInfo()返回URI后面的额外路径信息,用于访问您的Servlet,而getRequestURI()返回完整的URI。

考虑到一个Servlet必须首先配置自己的URI模式,我本以为它们会不同;我认为我从未将Servlet从根目录(/)服务过。

例如,如果Servlet“Foo”映射到URI“/ foo”,那么我本以为该URI是:

/foo/path/to/resource

会产生以下结果:

RequestURI = /foo/path/to/resource

PathInfo = /path/to/resource

22
值得一提的是有关解码行为。getRequestURI()不对字符串进行解码,而getPathInfo()进行解码。 - Kavindu Dodanduwa
2
在某些情况下,getRequestURI()像预期的那样给出字符串"/foo/path/to/resource",但是对于相同的HttpServletRequest对象,getPathInfo()却返回null。这到底是怎么回事? 编辑:由用户“30thh”在下面回答了该问题。 - Snackoverflow

42

让我们分解一下客户端在地址栏中输入以访问你的servlet的完整URL:

http://www.example.com:80/awesome-application/path/to/servlet/path/info?a=1&b=2#boo

这些部分包括:

  1. 协议: http
  2. 主机名: www.example.com
  3. 端口号: 80
  4. 上下文路径: awesome-application
  5. servlet路径: path/to/servlet
  6. 路径信息: path/info
  7. 查询字符串: a=1&b=2
  8. 片段: boo

请求URI(getRequestURI返回的)对应于第4、5和6部分。

(顺便提一下,虽然您没有要求,但getRequestURL方法将给出第1、2、3、4、5和6部分。)

现在:

  • 第四部分(上下文路径)用于从许多其他应用程序中选择您特定的应用程序,这些应用程序可能在服务器上运行
  • 第五部分(servlet路径)用于从您的应用程序的WAR中捆绑的许多其他servlet中选择特定的servlet
  • 第六部分(路径信息)由您的servlet逻辑解释(例如,它可能指向由您的servlet控制的某些资源)。
  • 第七部分(查询)也可以使用getQueryString将其提供给您的servlet
  • 第八部分(片段)甚至不会发送到服务器,并且仅与客户端相关和已知

以下内容始终成立(除了URL编码差异):

requestURI = contextPath + servletPath + pathInfo

以下来自Servlet 3.0规范的示例非常有帮助:


注意:下面有一张图片,我没有时间用HTML重新制作。

enter image description here


18

考虑以下servlet配置:

   <servlet>
        <servlet-name>NewServlet</servlet-name>
        <servlet-class>NewServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>NewServlet</servlet-name>
        <url-pattern>/NewServlet/*</url-pattern>
    </servlet-mapping>

现在,当我访问URL http://localhost:8084/JSPTemp1/NewServlet/jhi时,它会按照上述模式映射,并调用NewServlet

这里:

getRequestURI() =  /JSPTemp1/NewServlet/jhi
getPathInfo() = /jhi

我们有以下这些方法:

  • getPathInfo()

    返回
    一个字符串,由 Web 容器解码,指定请求 URL 中在 Servlet 路径之后但在查询字符串之前的额外路径信息;如果 URL 没有任何额外路径信息,则返回 null。

  • getRequestURI()

    返回
    包含从协议名称到查询字符串的 URL 部分的字符串。


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