专栏首页天马行空布鲁斯关于URL Encoding的那些事

关于URL Encoding的那些事

之前遇到一个关于URL encoding的一个问题,很tricky,这里把这个问题的root cause以及对这个问题的一些思考记录下来,分享给大家。

首先,抽象这个问题的原型如下:

有一个电商平台,我们需要调用其暴露的一个API来创建电商信息,API要求我们把电商名作为URL参数传过去,然后创建相应的一条电商记录。这个API示例如下:

POST http://localhost:8080/stores/{storeName}

返回结果:

{
  "storeName": "xxx",
  "otherInfo": ""
}

在测试这个API的过程中发现,有一个电商名(abc{d)包含字符“{”,出现了一个问题:用postman发送请求过去能够成功;但是通过java代码发送请求则报错,提示说URL syntax出错,URL不允许包含“{”字符。

POST http://localhost:8080/stores/abc{d

后来发现,postman能成功的原因是由于postman自动帮忙做了个URL encoding,通过创建出来的那条记录可以验证,创建出来的记录如下。

{
  "storeName": "abc%7Bd",
  "otherInfo": ""
}

而java代码没有做encoding,所以就报错了。因为根据URL的RFC规范,“{”字符确实不允许,必须做encoding。See https://tools.ietf.org/html/rfc3986#section-2。

那么,怎么解决这个问题呢,如何允许传入包含“{”字符的电商名呢?当时想到的解决方案是,在代码中显式的把电商名都做一个URL encoding,然后再作为URL参数传过去。很好,用这个方案把这个问题解决了。请求URL参数电商名是encoded过的(abc%7Bd),创建出来也是encoded过的(abc%7Bd)。

没过多久,又出现了另外一个问题。在测试过程中,有一个电商名(abc:d)包含字符“:”,按照之前的逻辑,我们把“:”做一个encoding(abc%3Ad)发送过去,期望创建的记录应该是encoded的名字,但是结果却不是,结果是一个decoded的名字(abc:d),即包含“:”本身。

结果因为这个,程序出错了。同时测试还发现,通过postman发送请求过去没有问题,发送带字符“:”的名字(abc:d)过去,创建出来的就是带“:”(abc:d);发送字符“:”的encoded串(abc%3Ad)过去,得到的就是encoded的串(abc%3Ad)。但是,通过代码发送字符“:”(abc:d)或者字符“:”(abc%3Ad)的encoded的串,创建出来的都是“:”(abc:d)。到这里就有点思路了,发现字符“:”好像在哪里被自动decode了。

经过调试发现,问题出在一个底层依赖的library的版本上,java发送http请求的方法最终依赖于一个library叫做org.apache.httpcomponents:httpclient,高版本(4.5.8)的library会自动decode一些字符(包括“:”),低版本(4.5.5)的则不会。

那么到这里,问题就明白了,问题的root cause即是虽然我们显式把字符“:”做了一个encoding,但是在请求被真正发出去之前被Httpclient自动decode了,所以创建出来的记录都是“:”。

对这个问题的一些思考:

第一,为啥字符“:”的encoded串会被自动decode,而字符“{”却没有?

原因是,“:”是URL规范允许的字符,尽管其是保留字符。而“{”是不允许字符,必须做URL encoding,中文汉字也是一样,必须做URL encoding。

第二,如果传入的是一个中文字符的encoded串,创建出来的就是encoded的串,很显然这个不易读,所以我们需要把这个encoded的串做一个decode。那么设想一下,服务端每次都需要显示做decode吗?记得之前在Spring mvc项目中没有显示decode啊?

原因是Spring mvc自动把URL参数都做了一个decoding,所以我们不用显示decode。而这个问题中的API在实现端没有利用自动decode功能,即拿的是原生的参数值,所以一些时候会存在不易读。自动decoding会有什么问题吗?在大多数情况下应该是没问题,即输入“{”的encoded串,后端得到的是就是“{”。那么如果本身参数值就是“{”的encoded串呢,也没问题,发请求方自己需要对这个串做一次encoding作为输入。

第三,发现自动decoding在不同技术栈平台(Spring boot / mvc, .net core / mvc, .net framework / mvc, Nodejs)实现不一样 ,有时候也会出现不一致的情况。比如说,当请求的URL参数包含%3F(字符“?”的encoded串),在Spring boot和 .net core都能够正常拿到字符“?”;在.net framework里却会报错。而当请求的URL参数包含%2F(字符“/”的encoded串),在Spring boot, .net core和 .net framework里都不工作;在Nodejs里,用相对比较原生的方式,就可以工作并且获取到这个URL参数。如下:

P1:Spring boot中字符“?”是work的

P2:Spring boot中字符“/”不work,报404

P3:Nodejs中可以拿到包含字符“/”的参数

所以有时候利用平台的自动decoding可能会出现一些问题,这时候你可能需要考虑利用平台相对比较原生的方式操作httprequest对象,比如上面nodejs的方式。

最后,其实关于编码,之前也写过一篇关于utf8编码的文章(关于编码的那些事),这里讨论的是URL encoding。编码,个人理解其本质就是把一种表现形式的内容通过某种方式转换成另外一种形式,以达到某些目的,比如URL encoding把字符“{”转成“%7B”,这样才符合http规范,URL才能被正确解析及转发到服务器;比如utf8编码把字符“汉”转成“e6b189”,这样才能被计算机存储,因为计算机只能识别一个字节一个字节。除了utf8编码、URL encoding,我们常用到的还有另外一种编码方式:base64编码,这个编码主要用于混淆易读的一些信息,比如jwt token。

注意,我们在很多地方还用到哈希算法,比如SHA1等,编码和哈希最大的区别就是:编码是可逆的,哈希不可逆。

References

  • URL规范:https://tools.ietf.org/html/rfc3986#section-2

本文分享自微信公众号 - 天马行空布鲁斯(gh_2feda5c053bd)

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2019-12-05

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Scrapy笔记三 自动多网页爬取-本wordpress博客所有文章

    学习自http://blog.csdn.net/u012150179/article/details/34486677

    十四君
  • CentOS LNMP (Linux+Nginx+MariaDB+PHP)

    安装目录: /usr/local/openresty/ html 目录:/usr/local/openresty/nginx/html

    iOSDevLog
  • Scrapy-笔记二 中文处理以及保存中文数据

    学习自:http://blog.csdn.net/u012150179/article/details/34450547

    十四君
  • PHP规范PSR0和PSR4的理解

    一、PSR0简介 下文描述了若要使用一个通用的自动加载器(autoloader),你所需要遵守的规范: 一个完全标准的命名空间(namespace)和类(cl...

    猿哥
  • 马蜂窝消息总线——面向业务的消息服务设计

    蜂窝消息总线于 2017 年 11 月份上线,截至目前,已经被电商、酒店、大交通、社区等多个技术团队投入到生产环境的使用中。

    Spark学习技巧
  • 数据结构和算法——选择排序

    选择排序的工作方式是:维护已排序的子列表,从主列表中找到最小的项,然后将其交换到子列表的最后一个元素,直到对所有项进行排序为止。

    Lemon黄
  • python语音智能对话聊天机器人,linux&&树莓派双平台兼容

    项目简介:运用百度语音进行声音转中文的识别与合成,智能对话使用图灵机器人,录音则,linux端用pythonaudio 模块.树莓派端因为pythonaudio...

    十四君
  • Web安全——逻辑漏洞浅析

    有的可用手机验证码登录,我们用burp抓取数据包然后放到Repeater这个模块里,反复点go,要是存在短信轰炸漏洞就会有一大堆短信

    天钧
  • 千万级批量采集框架,就叫他UrlSpider吧

    我希望在整个理清楚数据采集这个行业的过程中,实现一个能高效的分布式的自带反爬虫的框架。。

    十四君
  • 2019年末逆向复习系列之淘宝M站Sign参数逆向分析

    本次案例的代码都已上传到Review_Reverse上面,后面会持续更新,大家可以Fork一波。

    云爬虫技术研究笔记

扫码关注云+社区

领取腾讯云代金券