我们假设我有像'=&?/;#+%'这样的字符串作为我网址的一部分,让我们这样说:
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。
答案 0 :(得分:21)
浏览器和服务器的'%2F'和'/'之间存在根本区别。
HttpServletRequest规范说(没有任何逻辑,AFAICT):
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编码的标准。
在完整的网址中,您必须出于不同的原因区分转义和非转义字符,包括:
Java处理前两种情况很好:
getPathInfo()
仅返回路径部分,已解码getParameter(String)
访问部分查询部分与第三种情况不太一致。如果你想在'/'作为两个路径段的分离和路径段(%2F)内的'/'之间做出区别,那么你不能一致地将路径表示为一个解码的字符串。您可以将其表示为一个编码字符串(例如“foo / bar%2Fbaz”),或者将其表示为已解码段(例如“foo”,“bar / baz”)。 但是因为getPathInfo()API承诺只做(一个解码的字符串),所以它别无选择,只能将'/'和'%2F'视为相同。
对于常见的Web应用程序,这很好。如果您在极少数情况下确实需要做出改变,那么您可以自己解析URL,获取原始版本getRequestURI()
。如果那个提供了你声明解码的URL,那么这意味着你正在使用的servlet实现中存在一个错误。