5

假设我有像 '=&?/;#+%' 这样的字符串作为我的 URL 的一部分,让我们这样说:

example.com/servletPath/someOtherPath/myString/something.html?a=b&c=d#asdf

其中 myString 是上面的字符串。我已经编码了关键部分,所以 URL 看起来像

example.com/servletPath/someOtherPath/%3D%26%3F%2F%3B%23%2B%25/something.html?a=b&c=d#asdf

到现在为止还挺好。

当我在 servlet 中读取任何request.getRequestURI(),request.getRequestURL()request.getPathInfo()时,返回的值已经被解码,所以我会像

someOtherPath/=&?/;#+%/something.html?a=b&c=d#asdf

而且我无法区分真正的特殊字符和编码字符。

我通过完全禁止上面的字符解决了特定问题,这在这种情况下有效,但我仍然想知道有没有办法在 servlet 类中获取未解码的 URL。

另一个编辑:当我昨晚遇到这个问题时,我太累了,没有注意到真正发生了什么,这更奇怪!我已经映射了 servlet,比如 /servletPath/* 之后,我可以放置我想要的任何内容,并根据路径的其余部分让我的 servlet 响应,除非路径中有 %2F。在那种情况下,请求永远不会命中 servlet,我得到 404!如果我输入 '/' 而不是 %2F 它可以正常工作。我在 Linux 上的 Java 1.6.0-04 上运行 Tomcat 6.0.14。

4

5 回答 5

22

对于浏览器和服务器,'%2F' 和 '/' 之间存在根本区别。

HttpServletRequest 规范说(没有任何逻辑,AFAICT):

  • getContextPath:未解码
  • getPathInfo:解码
  • getPathTranslated:未解码
  • getQueryString:未解码
  • getRequestURI:未解码
  • getServletPath:解码

getPathInfo() 的结果应该被解码,但 getRequestURI() 的结果不能被解码。如果是,您的 Servlet 容器违反了规范(正如 Wouter Coekaerts 和 Francois Gravel 正确指出的那样)。您正在运行哪个 Tomcat 版本?

更令人困惑的是,出于安全原因,当前的 Tomcat 版本拒绝包含某些特殊字符编码的路径。

于 2009-06-30T16:08:36.503 回答
2

如果解码%2F后的url中有a ,则表示编码后的url包含。%252F

既然%2F/为什么不只是拆分"\/"而不担心 URL 编码呢?

于 2009-06-08T17:58:15.873 回答
1

根据Javadoc, getRequestURI 不应解码字符串。另一方面,getServletPath 返回一个解码的字符串。我使用 Jetty 在本地对此进行了测试,它的行为如文档中所述。

因此,由于您描述的行为与 Sun 文档不匹配,因此您的情况可能还有其他原因。

于 2009-06-09T11:19:29.183 回答
0

看起来你正在尝试做一些 RESTy (使用 Jersey)。您是否可以仅解析 URL 的前导和尾随部分以获取您要查找的数据?

url.substring(startLength, url.length - endLength);

于 2009-06-08T20:51:51.467 回答
-1

更新:这个答案最初错误地指出路径中的 '/' 和 '%2F' 应该始终被视为相同。它们实际上是不同的,因为路径是 / 分隔的段的列表。

您不必在 URL的路径部分中区分编码字符和未编码字符。路径中没有可以在 URL 中具有特殊含义的字符。例如,'%2F' 必须解释为与 '/' 相同,并且访问此类 URL 的浏览器可以随意替换一个它认为合适的 URL。在它们之间产生差异正在打破 URL 编码的标准。

在完整的 URL 中,出于不同的原因,您必须区分转义字符和非转义字符,包括:

  • 查看路径部分的结束位置。因为一个?在路径中编码不应被视为结束。
  • 在查询字符串中。因为参数的部分值可能包含'&'或'=',...
  • 在路径中,'/' 分隔两个段,而 '%2F' 可以包含在一个段中

Java 可以很好地处理前两种情况:

  • getPathInfo()仅返回路径部分,已解码
  • getParameter(String)访问部分查询部分

第三种情况就不好处理了。如果您想将“/”作为两个路径段的分隔符与路径段内的“/”(%2F)进行区分,那么您不能始终将路径表示为一个解码字符串。您可以将其表示为一个编码字符串(例如“foo/bar%2Fbaz”),也可以将其表示为解码段的列表(例如“foo”、“bar/baz”)。但是因为 getPathInfo() API 承诺这样做(一个解码字符串),所以它别无选择,只能将 '/' 和 '%2F' 视为相同。

对于通常的 Web 应用程序,这很好。如果您在极少数情况下确实需要有所作为,您可以自己解析 URL,使用getRequestURI(). 如果那个提供了您声称的解码的 URL,那么这意味着您正在使用的 servlet 实现中存在错误。

于 2009-06-09T11:36:04.843 回答