Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 430|回复: 0

Java中常见的URL问题及解决方案

[复制链接]
  • TA的每日心情
    奋斗
    2024-6-6 10:50
  • 签到天数: 750 天

    [LV.10]以坛为家III

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    706216
    发表于 2021-8-28 10:35:28 | 显示全部楼层 |阅读模式

    URL无处不在,不过似乎开发人员并没有真正地理解它们,因为在Stack Overflow上经常看到有人在问如何正确的创建一个URL。想知道URL语法是如何工作的,可以看下兄弟连教育总结的这篇文章,非常不错。

     

    本文不会深入介绍URL的全部语法,这是我们发布的一个用于正确地创建URL的Java库。

     

    问题1:Java的URLEncoder

    这个类不仅名字取的很差,而且它的文档上来第一句话就不太对头。

     

    Utility class for HTML form encoding.

    你可能正纳闷为什么叫URLEncoder呢,看到这行就彻底无语了。

     

    如果你读过兄弟连教育(www.itxdl.cn)的那篇博文,现在你应该明白了,你没法通过这个类将一个URL串奇迹般地转化成一个安全,正确编码的URL对象,当然如果你没做足功课的话,这里有个小例子可以帮助你理解下。

     

    假设你有个HTTP的服务端点,它接受一个查询参数p,p的值就是要查找的字符串。如果你搜索"You & I"这个串的话,你第一次创建的搜索的URL可能是这样:。这个当然没法工作,因为&是分隔查询参数name/value对的分隔符。如果你拿到这个错乱的URL串的话,你对它简直束手无策,因为首先你就没法正确的解析它。

     

    那好,我们来使用下URLEncoder。URLEncoder.encode("You & I", "UTF-8")是结果是You+%26+I。这个%26解码之后就是&,而+号在查询串中代表的就是空格,因此这个URL是能正常工作的。

     

    现在假设你想使用你的查询串来拼接URL路径,而不是放到URL参数里面。很明显,是错误的。不幸的是,URLEncoder.encode()的结果也是错的。解码后会得到/search/You+&+I,因为+号在URL路径中是不会解析成空格的。

     

    URLEncoder或许能满足你的一些场景。但不幸的是,它这个过于通用的名字使得开发人员很容易误用它。因此最好的方法就是不要使用它,免得后面别的开发人员在你的基础上又使用了别的功能时犯错(除非,你真的是在进行"HTML表单编码")。

     

    问题2:Groovy HttpBuilder以及Java的URI

    HTTP Builder是Groovy的一个HTTP客户端库。

     

    创建一个普通的GET请求非常简单:

     

    new HTTPBuilder.request(Method.GET) {

      uri.path = "/foo"

    }

    这段代码会发送GET /foo HTTP/1.1到服务端(你可以运行nc -l -p 18080之后再执行这段代码验证下)。

     

    我们来试一下包含空格的URL。

     

    new HTTPBuilder.request(Method.GET) {

      uri.path = "/foo bar"

    }

    这个发送的是GET /foo%20bar HTTP/1.1,看起来还不错。

     

    现在假设我们的路径中有一段就叫做foo/bar。这可不能简单地发送foo/bar就完了,因为这会被认为成路径中包含两段,foo和bar,那我们试下foo%2Fbar吧(把/替换成对应的编码)。

     

    new HTTPBuilder.request(Method.GET) {

      uri.path = '/foo%2Fbar'

    }

    这个发送的则是GET /foo%252Fbar HTTP/1.1。这可不太妙。%2F中的%被重复编码了,这样解码后拿到的路径是foo%2Fbar而不是foo/bar。这里其实真正要怪的是java.net.URI,因为这个HTTPBuilder里的URIBuilder类用的就是它。

     

    上述代码中的配置闭包中暴露的uri属性的类型是URIBuilder。如果你通过uri.path = ...来更新uri的path属性的话,它最终会调用URI的一个构造方法,这个方法对于传入的path属性是这么描述的:

     

    如果提供了path参数,则将它追加到URL后面。path里面的字符,只要不是非保留,标点,转义及其它分类(译注:这几个分类在RFC 2396中有详细说明)的字符,同时又不是/或者@号的,都会进行编码。

    这个做法意义不大,因为如果未编码前的文本包含特殊字符的话,它就无法生成一个正确编码的路径分段。换句话说,“我会对这个字符串进行编码,而编码之后它就是正确的”,这当然是个谬论,而URI正好是这个谬论的牺牲品。如果字符串已经正确编码了,那就没什么问题,如果不是的话,那就完蛋了,因为这个串没法解析。事实上,文档里说的不会对/号转义的意思是,它假设path串已经正确地编码了(就是说正确地使用/来分隔路径),同时又还没有正确地编码(除了/外的其它部分仍然需要进行编码)。

     

    如果HTTPBuilder不使用URI类的这个存在缺陷的功能就好了,当然了,如果URI自己本身没问题的话就更好了。

     

    正确的做法

    我们写了这个url-builder,它能帮助开发人员方便的拼接各种类型的URL。它遵循了篇首那几个参考资料中的编码规范,同时它还提供了流式的API。下面这个使用示例几乎可以涵盖所有的使用场景了:

     

    UrlBuilder.forHost("http", "foo.com")

        .pathSegment("with spaces")

        .pathSegments("path", "with", "varArgs")

        .pathSegment("&=?/")

        .queryParam("fancy + name", "fancy?=value")

        .matrixParam("matrix", "param?")

        .fragment("#?=")

        .toUrlString()

     

    这个例子演示了URL各个部分的不同的编码规则,比如说在路径中未编码的&=是允许的,而?/则是需要编码的,但在查询参数中=是需要编码的,但?号则不需要,因为这里已经是查询串的部分了。

    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-6-16 06:27 , Processed in 0.059421 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表