我的Java独立应用程序从用户获取一个URL(指向文件),我需要点击它并下载它 . 我面临的问题是我无法正确编码HTTP URL地址......
例:
URL: http://search.barnesandnoble.com/booksearch/first book.pdf
java.net.URLEncoder.encode(url.toString(), "ISO-8859-1");
回报我:
http%3A%2F%2Fsearch.barnesandnoble.com%2Fbooksearch%2Ffirst+book.pdf
但是,我想要的是
http://search.barnesandnoble.com/booksearch/first%20book.pdf
(空间由%20取代)
我猜 URLEncoder
不是为了编码HTTP URL而设计的...... JavaDoc说"Utility class for HTML form encoding" ......有没有其他办法可以做到这一点?
24 回答
也许可以在org.springframework.web.util中尝试UriUtils
我阅读以前的答案来编写我自己的方法,因为我无法使用前面的答案的解决方案正常工作,它看起来不错,但如果你能找到不适合这个的URL,请告诉我 .
我将在这里针对Android用户添加一个建议 . 您可以这样做,避免必须获得任何外部库 . 此外,在上面的一些答案中提出的所有搜索/替换字符解决方案都是危险的,应该避免 .
尝试一下:
你可以看到,在这个特定的URL中,我需要对这些空间进行编码,以便我可以将它用于请求 .
这利用了Android类中可用的一些功能 . 首先,URL类可以将url分解为其正确的组件,因此您无需进行任何字符串搜索/替换工作 . 其次,当您通过组件而不是单个字符串构造URI时,此方法利用了正确转义组件的URI类功能 .
这种方法的优点在于,您可以使用任何有效的url字符串并使其工作,而无需自己了解任何特殊知识 .
如果有人不想在项目中添加依赖项,这些函数可能会有所帮助 .
我们将URL的“路径”部分传递到此处 . 您可能不希望将完整的URL作为参数传递(查询字符串需要不同的转义等) .
并测试:
不幸的是,
org.apache.commons.httpclient.util.URIUtil
已被弃用,replacement org.apache.commons.codec.net.URLCodec
的编码适用于表单帖子,而不是实际的URL 's. So I had to write my own function, which does a single component (not suitable for entire query strings that have ?'和&s)您还可以使用
GUAVA
和路径escaper:UrlEscapers.urlFragmentEscaper().escape(relativePath)
我有同样的问题 . 通过unsing解决了这个问题:
它对字符串进行编码,但跳过“:”和“/” .
如果您的URL中有编码的“/”(%2F),则仍然存在问题 .
RFC 3986 - 第2.2节说:“如果URI组件的数据与保留字符作为分隔符的目的冲突,那么冲突数据必须在形成URI之前进行百分比编码 . ” (RFC 3986 - 第2.2节)
但是Tomcat存在一个问题:
因此,如果您有一个带有%2F字符的URL,Tomcat将返回:“400无效的URI:noSlash”
您可以在Tomcat启动脚本中切换错误修复:
是的URL编码将编码该字符串,以便它可以在URL中正确传递到最终目的地 . 例如,你没有http://stackoverflow.com?url=http://yyy.com . UrlEncoding参数将修复该参数值 .
所以我有两个选择:
您是否可以访问与域名分开的路径?如果是这样,您可以简单地将UrlEncode路径 . 但是,如果不是这种情况,那么选项2可能适合您 .
获取commons-httpclient-3.1 . 这有一个类URIUtil:
System.out.println(URIUtil.encodePath(“http://example.com/x y ", " ISO-8859-1”));
这将输出您正在寻找的内容,因为它只会编码URI的路径部分 .
仅供参考,您需要使用commons-codec和commons-logging来使此方法在运行时工作 .
请注意,上面的大部分答案都是不正确的 .
URLEncoder
类,尽管是名字,但不是必须在这里 . 令人遗憾的是,Sun这个课程非常令人讨厌 .URLEncoder
用于将数据作为参数传递,而不是用于对URL本身进行编码 .换句话说,
"http://search.barnesandnoble.com/booksearch/first book.pdf"
是URL . 参数例如是"http://search.barnesandnoble.com/booksearch/first book.pdf?parameter1=this¶m2=that"
. 参数是您将使用的URLEncoder
.以下两个例子突出了两者之间的差异 .
根据HTTP标准,以下内容产生错误的参数 . 请注意,&符号(&)和加号()编码不正确 .
以下将生成正确的参数,并正确查询编码 . 请注意空格,&符号和加号 .
我已经创建了一个新项目来帮助构建HTTP URL . 该库将自动对路径段和查询参数进行URL编码 .
您可以在https://github.com/Widen/urlbuilder查看源代码并下载二进制文件
此问题中的示例网址:
产生
http://search.barnesandnoble.com/booksearch/first%20book.pdf
我开发了一个用于此目的的库:galimatias . 它以与Web浏览器相同的方式解析URL . 也就是说,如果URL在浏览器中工作,它将被galimatias正确解析 .
在这种情况下:
会给你:
http://search.barnesandnoble.com/booksearch/first%20book.pdf
. 当然这是最简单的情况,但它可以用于任何事情,超越java.net.URI
.你可以在以下网址查看:https://github.com/smola/galimatias
java.net.URI课程可以提供帮助;在您找到的URL文档中
使用具有多个参数的构造函数之一,例如:
(URI的单参数构造函数不会转义非法字符)
只有非法字符才会被上面的代码转义 - 它不会转义非ASCII字符(请参阅fatih的评论) .
toASCIIString
方法可用于仅使用US-ASCII字符获取String:对于具有
http://www.google.com/ig/api?weather=São Paulo
之类的查询的URL,请使用构造函数的5参数版本:你可以使用这样的功能 . 根据您的需要完成并修改它:
使用示例:
其结果是:http://www.growup.com/folder/int%C3%A9rieur-%C3%A0_vendre?o=4
我把上面的内容改成了一下 . 我首先喜欢积极的逻辑,我认为HashSet可能比其他一些选项提供更好的性能,比如搜索String . 虽然,我不确定自动装箱惩罚是否值得,但如果编译器优化ASCII字符,那么装箱的成本将会很低 .
String url =“”http://search.barnesandnoble.com/booksearch/;
这将是不变的我猜,只有文件名动态改变,所以得到文件名
字符串文件; //获取文件名
String urlEnc = url fileName.replace(“”,“%20”);
怎么样:
public String UrlEncode(String in_){
}
挑剔:根据定义,包含空白字符的字符串不是URI . 所以你要找的是实现Section 2.1 of RFC 3986中定义的URI转义的代码 .
如果您有URL,则可以将url.toString()传递给此方法 . 首先解码,以避免双重编码(例如,编码空格导致%20并编码百分号导致%25,因此双重编码将空格转换为%2520) . 然后,使用上面解释的URI,添加URL的所有部分(这样就不会删除查询参数) .
除了Carlos Heuberger的回复:如果需要不同于默认值(80),则应使用7参数构造函数:
正如您遗憾地发现的那样,URLEncoding可以很好地编码HTTP URL . 您传入的字符串“http://search.barnesandnoble.com/booksearch/first book.pdf”已正确完整地编码为URL编码形式 . 你可以传递你在URL中作为参数返回的整个长串gobbledigook,它可以被解码回你传入的字符串 .
听起来你想要做一些与将整个URL作为参数传递一点点不同的东西 . 根据我收集的内容,您尝试创建一个看起来像“http://search.barnesandnoble.com/booksearch/whateverTheUserPassesIn ". The only thing that you need to encode is the " whateverTheUserPassesIn”位的搜索URL,所以您可能需要做的就是这样:
那会产生一些对你更有效的东西 .
我同意马特的观点 . 实际上,我从未在教程中看到过很好的解释,但有一个问题是如何对URL路径进行编码,而一个非常不同的是如何编码附加到URL的参数(查询部分,后面的“? “符号) . 他们使用类似的编码,但不一样 .
特别适用于空白字符的编码 . URL路径需要将其编码为%20,而查询部分允许%20以及“”符号 . 最好的想法是使用Web浏览器自行测试我们的Web服务器 .
对于这两种情况,我 ALWAYS 将编码 COMPONENT BY COMPONENT ,而不是整个字符串 . 实际上URLEncoder允许用于查询部分 . 对于路径部分,您可以使用类URI,尽管在这种情况下它会要求整个字符串,而不是单个组件 .
无论如何,我相信 the best way to avoid these problems is to use a personal non-conflictive design. 怎么样?例如,我永远不会使用除-Z,A-Z,0-9和_之外的其他字符来命名目录或参数 . 这样,唯一的需要是对每个参数的值进行编码,因为它可能来自用户输入,并且使用的字符是未知的 .
使用以下标准Java解决方案(传递Web Plattform Tests提供的大约100个测试用例):
1. 将URL拆分为结构件 . 使用
java.net.URL
.2. 正确编码每个结构部件!
3. 使用
IDN.toASCII(putDomainNameHere)
对Punycode编码主机名!4. 使用
java.net.URI.toASCIIString()
进行百分比编码,NFC编码的unicode - (更好的是NFKC!) .在这里找到更多:https://stackoverflow.com/a/49796882/1485527
我开发的解决方案比任何其他解决方案更稳定: