Java从Servlet读取未解码的URL

时间:2009-06-08 17:50:59

标签: java url servlets encode decode

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

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()中的任何一个时,返回的值已经被解码,所以我得到了像

一样的strilng
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。

5 个答案:

答案 0 :(得分:21)

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

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

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

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

让问题更加令人困惑,当前的Tomcat版本会拒绝包含某些特殊字符for security reasons的编码的路径。

答案 1 :(得分:2)

如果已解码的网址中有%2F,则表示已编码的网址包含%252F

由于%2F/为什么不在[{1}}上拆分而不担心网址编码?

答案 2 :(得分:1)

根据Javadoc,getRequestURI不应解码字符串。另一方面,getServletPath返回一个已解码的字符串。我使用Jetty在本地测试它,它的行为与文档中描述的一样。

因此,您所描述的行为与Sun文档不匹配,因此您的情况可能还有其他因素在起作用。

答案 3 :(得分:0)

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

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

答案 4 :(得分:-1)

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

您不必在URL的路径部分中对已编码和未编码的字符进行区分。路径中没有可以在URL中具有特殊含义的字符。例如。 '%2F'必须与'/'解释相同,并且访问此类URL的浏览器可以根据需要随意替换另一个。在它们之间做出改变打破了URL编码的标准。

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

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

Java处理前两种情况很好:

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

与第三种情况不太一致。如果你想在'/'作为两个路径段的分离和路径段(%2F)内的'/'之间做出区别,那么你不能一致地将路径表示为一个解码的字符串。您可以将其表示为一个编码字符串(例如“foo / bar%2Fbaz”),或者将其表示为已解码段(例如“foo”,“bar / baz”)。 但是因为getPathInfo()API承诺只做(一个解码的字符串),所以它别无选择,只能将'/'和'%2F'视为相同。

对于常见的Web应用程序,这很好。如果您在极少数情况下确实需要做出改变,那么您可以自己解析URL,获取原始版本getRequestURI()。如果那个提供了你声明解码的URL,那么这意味着你正在使用的servlet实现中存在一个错误。