聊聊阿里云 OSS 的转义设计问题

今天同事向我反馈,当我们的静态资源有中文名混杂 + 和空格 时,得到的链接并不能打开,返回的是 404.

举个例子,假定我们的资源为:

http://example-resource.oss-cn-shanghai.aliyuncs.com/23232323/中文 + 文件-file.ec296f20-d67b-11e8-a623-7b28809dc3c9.js

那么在浏览器中访问的文件名应该被转义为:

%E4%B8%AD%E6%96%87%20+%20%E6%96%87%E4%BB%B6-file.ec296f20-d67b-11e8-a623-7b28809dc3c9.js

注意,在这里,空格被转义为 %20,而 + 没有进行任何处理。

同时,JavaScript 中的 encodeURInew URL() 都是符合这一规则的。

但是在阿里云 OSS 中,你可以在 404 页面看到他们后端请求的文件:

15402962480160.jpg

此时的一个问题:到底是存错了还是取错了——其实在这里我们基本可以看出取的是有问题的,因为对于这个 path 的语义应该是+,却被错误的处理成了空格,不过考虑到严谨性,还是确认了一下存储的 Object,确定是取的问题。

接下来的问题是:

  1. SDK 给我们返回的阿里云链接是可以直接访问的,而我们自定义拼接的链接是不可访问的,他们做了什么特殊处理
  2. 到底是哪里出了问题

因此,不得已的只能把 Node SDK 源码看了一遍……终于发现了他们的骚操作:

15402967203618.jpg

https://github.com/ali-sdk/ali-oss/blob/master/lib/client.js#L366

在 encode 之后人工 2B,谁都比不过——

第二个问题,到底是谁的错?

于是正好上 so 搜了一下,发现了一波标准:https://stackoverflow.com/questions/2678551/when-to-encode-space-to-plus-or-20

+ means a space only in application/x-www-form-urlencoded content, such as the query part of a URL
Now, the HTML 2.0 Specification (RFC1866) explicitly said, in section 8.2.2, that the Query part of a GET request's URL string should be encoded as ·application/x-www-form-urlencoded·. This, in theory, suggests that it's legal to use a '+' in the URL in the query string (after the '?').

也就是说,只有 application/x-www-form-urlencodedquerystring 中的空格 = ++ = %2B,其他情况下 + 不应该被特殊处理,很显然阿里云 OSS 的实现是错误的。

得到问题的答案之后,基本定位到是 OSS 后端的转义问题,但是去怼 OSS 的时候,他们用「这是 Feature」、「为了复杂规则更好的兼容」、「设计就是这样」、「用户最好自己 encode」来答复,这里有涉及到内容存储的另一个结构了:

对于内容存储而言,会将路径也作为文件名的一部分,即上例中的文件名是:

23232323/中文 + 文件-file.ec296f20-d67b-11e8-a623-7b28809dc3c9.js

那么我们处理的时候,如果使用 encodeURI,则不会转义 +,如果使用 encodeURIComponent,则会把 / 一起转义,如果在保存前转义,就无法保留正确的文件名——非常矛盾,这大概也就是为什么 SDK 用了 + => 2B 的黑魔法吧。

不过我也有个大胆的猜测,因为阿里云这段代码非常年长而稳定了,而我们这样的考据用户其实并不多,凑合用黑魔法也能用,所以所谓的「Feature」,就是——改了万一挂了我可背不起锅,即使是加一个兼容 Feature,也是有可能挂的,所以最好的方法还是让用户继续用黑魔法,但是建议大家以后在做类似的实现的时候不要理所当然的以为 url 中的 + 必然等于空格,在标准中是有明确规定的。

小插曲:最开始以为是 JavaScript encode 库有问题,怎么都不能和阿里 encode 的结果一致,还骂了一声 JavaScript 辣鸡,如果是 PHP 估计就没问题(喂。定位了一天并且和阿里云撕逼之后只能说——阿里云辣鸡(喂。

植入部分

如果您觉得文章不错,可以通过赞助支持我。

如果您不希望打赏,也可以通过关闭广告屏蔽插件的形式帮助网站运作。

标签: 知识, 设计, OSS

已有 2 条评论

  1. 宋小爱

    膜天总,阿里云辣鸡

  2. 哈哈 也遇到这个坑了,还以为没有进行 url encode 才会的,发现 encode 了也会这样,只能特殊处理了

添加新评论