作为一名后端工程师遇到这样的问题也是挺难得的,大多因为应用框架帮我们做了许多前期的工作,比如今天要讨论的url编码。
可能每个Java开发者都用过一个东西:URL encode。把本来正常的 url 编码成非常长的一串东西,不知道你曾经有没有对此有过怀疑,为什么要编码?简单来说,编码是为了更方便的解析。对,你没听错,编成人类不可读的那么一长串字符确实会简化计算机的解析。从另一个方面说,增加冗余就是为了降低复杂度。
首先介绍一下背景。http 的世界里全部都是协议,没有为什么,就是这么规定的,大家都按照协议去办事,无规则不成方圆。当然,这个协议肯定也是征求了各方的意见才最终定稿,在定稿之前任何都可以去提意见,有兴趣的话可以去看看IETF(互联网工程任务组),这是一个开放的标准组织,负责开发和推广自愿互联网标准。不过我觉得你看到协议正文的时候就瞬间没兴趣了,尤其作为非英语母语的国家的开发者,可能顶多有问题会去查一查来源和说法。
回归正题,为什么要对 url 进行编码。RFC 2936里面是这么说的:
The space character is excluded because significant spaces may disappear and insignificant spaces may be introduced when URI are transcribed or typeset or subjected to the treatment of word- processing programs. Whitespace is also used to delimit URI in many contexts.
这个地方说的是空格对 url 的完整性带来的影响,举个例子:
http://www.youpage.com?name=i love my family
这个时候如果不编码,那只能识别到 name=i,这是一方面原因。另一方面原因是,url 中会包含特殊字符,比如 @,这也是不允许的。然后就是 url 不允许出现中文等非拉丁字符。
以上都是背景说明,下面重点来了。对于application/x-www-form-urlencoded的编码有这样的说明:
Control names and values are escaped. Space characters are replaced by `+'
默认都会把空格转换成+,但其实空格对应的标准的URLEncode是%20。在这个协议下,把我的 url 里面的空格给转化成了+,但这还没结束,其实+本身是有对应的 encode 的,+对应的%2B恰好我的服务经过另一个服务转了一手,最终解析出来的空格就全变成+。这一来一回,对于一个后端开发者来说需要花一定的时间去查文档,然后找到其中的矛盾点,解决方案其实很简单:
str.replaceAll("\+", "%20");
因为我期望显示的是空格,所以直接在给出去之前把+全部替换成对应的URLEncode就好了。协议确实是好东西,如果上层协议不统一,万千开发者得浪费多数时间!