为什么最流行的编码算法是刚好带两个符号破坏兼容性的 base64,而不是能够无视大小写的 base36、不带符号的 base62?这两个符号不仅严重影响兼容性使标准码表的 base64 不能直接拼在 url 中,还没有增加多少信息密度 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
drymonfidelia
V2EX    程序员

为什么最流行的编码算法是刚好带两个符号破坏兼容性的 base64,而不是能够无视大小写的 base36、不带符号的 base62?这两个符号不仅严重影响兼容性使标准码表的 base64 不能直接拼在 url 中,还没有增加多少信息密度

  •  1
     
  •   drymonfidelia 2024-08-30 13:58:42 +08:00 7677 次点击
    这是一个创建于 412 天前的主题,其中的信息可能已经有所发展或是发生改变。

    base64 的编码结果并不是二进制,码表长度是 2 的整数次方没有任何的加成。

    被 base64 坑了好几次,按=截断 key=value 数据的时候忘记指定 maxsplit=1 导致=后面的数据丢掉。

    49 条回复    2024-09-02 11:50:16 +08:00
    MoYi123
        1
    MoYi123  
       2024-08-30 14:07:32 +08:00
    不是有 base64url 吗?
    drymonfidelia
        2
    drymonfidelia  
    OP
       2024-08-30 14:09:42 +08:00
    @MoYi123 我说了 **标准码表** 啊,我是想讨论兼容性这么差的编码算法为什么会流行起来
    MoYi123
        3
    MoYi123  
       2024-08-30 14:12:25 +08:00   1
    @drymonfidelia 因为 n % 64 == n & (63), 而 base62 和 base36 不行, 就这么简单.
    vvhy
        4
    vvhy  
       2024-08-30 14:13:41 +08:00   3
    字符串分割可不是处理 url 的好方法
    Trim21
        5
    Trim21  
       2024-08-30 14:16:08 +08:00
    码表长度是 2 的整数次方当然有加成啊,这意味着不需要进行大整数运算。
    masterclock
        6
    masterclock  
       2024-08-30 14:20:04 +08:00   3
    base64 发明的时候 http 还没被发明出来
    bczhc
        7
    bczhc  
       2024-08-30 14:21:10 +08:00
    因为 base64 广泛啊,multipart 里就能用它。而且 64 是 2 整数次方能方便编解码,重新对二进制位分隔就好了。而且其他的 binary-to-text 编码也有,base58 ,base62 base85 base91 等。你说 base32 ,咋不直接用 base16 ,就直接是十六进制咯。最后,base64url 也是事实上的规范。
    drymonfidelia
        8
    drymonfidelia  
    OP
       2024-08-30 14:21:28 +08:00
    @Trim21 多用几位一起编码不会带来明显的性能损失吧,和兼容性比起来两个符号的问题显得更大
    tool2dx
        9
    tool2dx  
       2024-08-30 14:21:58 +08:00
    base62 解码写起来很麻烦的,代码量要比 base64 多。你写过一次,就知道为什么没有流行起来了。

    总最简原则来讲,base64 还是方便不少。
    sagaxu
        10
    sagaxu  
       2024-08-30 14:24:13 +08:00
    base64: 3 字节的东西编码进 4 字节
    hex(base16): 2 字节的东西编码进 4 字节
    bit 数是固定的,编码解码位运算很方便

    base36 ?你告诉我是几字节到几字节?
    占几个 bit 固定不固定?如果不固定,可变长时怎么标记位数?如果固定,那 base 一定是 2 的某个次方,比如 16/32/64/128
    ipwx
        11
    ipwx  
       2024-08-30 14:28:30 +08:00
    @drymonfidelia 本来位运算就比除法快一个数量级。

    更何况为了速度,base64 都上 SSE/AVX2/AVX512 向量指令集了。

    在编码方面,速度就是这么重要。
    ipwx
        12
    ipwx  
       2024-08-30 14:29:35 +08:00   1
    另外看楼主的背景是前端或者后端。

    如果楼主会写 C ,大概才能理解为啥 64 位一定比 62 位快很多了。
    Trim21
        13
    Trim21  
       2024-08-30 14:32:12 +08:00
    @drymonfidelia #8 你首先要理解 baseXX 的意义,是把原始数据作为一个大整数然后进行进制转换。

    base62 ,base63 跟 base65 可能差不多,但是 base64 有独特的性质。64=2^6 ,byte 的 255=2^8 意味着每 3 字节的原始数据一定能编码为 4 字节的 base64 。

    所以 base64 可以每 4byte 进行处理,用现成的 uint32 就行。换成 base62 你就要处理一个不定长的 big int ,因为 62 不是 2 的幂,没有 base64 这样的性质。
    proxytoworld
        14
    proxytoworld  
       2024-08-30 14:40:04 +08:00   2
    挺奇怪的,又不是没有 url 编码,啥东西 url 编码之后拼在 url 也不会有问题啊,而且 base64 一开始设计也不是给 http 用的,只是刚好能用在 http 上
    proxytoworld
        15
    proxytoworld  
       2024-08-30 14:40:44 +08:00
    没看懂影响兼容性,url 编码解码不费 cpu ,又不是 api 改参数了。
    n0099
        16
    n0099  
       2024-08-30 14:42:35 +08:00
    IvanLi127
        17
    IvanLi127  
       2024-08-30 14:46:13 +08:00   2
    这样说的话,主流 base64 不适合你这个用例,没必要上,谁逼你上的直接干他。坑你的人是主张在 url 里放乱七八糟东西的人,而不是 base64 。
    Y25tIGxpdmlk
        18
    Y25tIGxpdmlk  
       2024-08-30 14:48:29 +08:00
    base64 我记得好像是 3 位一组 3 位一组,然后不够的用=号补齐。用 62 的话,相似的设计,需要单独一个字符专门用来当补齐符号用。
    wy315700
        19
    wy315700  
       2024-08-30 14:52:10 +08:00
    因为 3 * 8 = 4 * 6

    而 2 ^ 6 = 64 所以挑了 64 个字符
    knva
        20
    knva  
       2024-08-30 15:19:06 +08:00
    挺怪的.
    liuidetmks
        21
    liuidetmks  
       2024-08-30 15:29:20 +08:00
    避免除法,
    你有 1G 数据流,直接当做一个整数,那是很麻烦的
    而且可以流式处理,不用等到所有数据都接受到了才编码
    CEBBCAT
        22
    CEBBCAT  
       2024-08-30 15:41:40 +08:00   1
    菜就多练,URL 传递 Base64 就用 Base64URL ,硬传不就等于自己给自己挖坑吗?用的哪个语言?没有便捷的库?
    lisongeee
        23
    lisongeee  
       2024-08-30 15:45:23 +08:00   4
    > 被 base64 坑了好几次,按=截断 key=value 数据

    看起来你的场景是在反序列化 url string 里的 search 参数,好奇为什么不用标准序列化对象?

    https://developer.mozilla.org/en-US/docs/Web/API/URL

    另外将 base64 编码到 url search 参数里的时候,也要调用标准序列化方法

    此时 base64 里的 = 字符会变成 %3D ,如果按照这个标准序列化,你的分割不会出现错误

    我猜测两边都是手动拼接/手动分割字符串去构造参数,而不是去使用标准序列化和反序列化方法

    我们这边后端一个系统 解析/构造 url 的时候不按照标准走,产生如 hash 丢失,参数解码错误破坏整个 url

    还有 飞书 的网页第三方登录,点击拒绝授权的时候,如果你的参数里面有 url ,url 里面有特殊字符,虽然你的按标准走的,但是煞笔飞书会手动解码两次后拼接,导致破坏整个 url 导致参数丢失

    每次跟这些不按标准喜欢自己拼接字符串的煞笔对接都气死我了
    adoal
        24
    adoal  
       2024-08-30 15:50:00 +08:00   2
    手拼 URL 不检查不转换参数偏要怪 base64 使用了不兼容 URL 的字符……那你手拼 SQL 直接传裸参试试。
    tool2dx
        25
    tool2dx  
       2024-08-30 15:55:07 +08:00
    @lisongeee RFC 标准有,就是 https://en.wikipedia.org/wiki/Base64 里的 base64url ,简单来说就是把'+'和'/'变成'-'和'_', 再把尾巴=去掉。

    在国外项目挺常见的,比如 lets encrypt acme 协议提交的 url ,就必须这样编码。
    lisongeee
        26
    lisongeee  
       2024-08-30 16:13:37 +08:00
    @tool2dx

    你的回复和我的回复没有一点关系,你是不是回复错人了

    ---

    另外 base64 尾部的 = 只是为了让这个 base64 string 的长度是 4 的倍数

    而现在的大多数解析器解析时都是支持忽略尾部 = 字符的,所以很多工具生成的 base64 都没有 = 字符
    tool2dx
        27
    tool2dx  
       2024-08-30 16:18:12 +08:00
    @lisongeee 嗯,我只是多一句嘴,回复确实没啥关系。
    AV1
        28
    AV1  
       2024-08-30 16:37:55 +08:00   2
    先不说 base64 ,你拼 URL 的时候不用 encodeURIComponent()再包裹一遍吗?被坑了几次都还没这个意识吗?
    FengMubai
        29
    FengMubai  
       2024-08-30 16:46:54 +08:00
    base16(hex): 变为原来的 2 倍
    base32: 1.6 倍
    base64: 1.333 倍
    base85: 1.25 倍

    base85 里有反斜线, base64 已经很折中了
    BugCry
        30
    BugCry  
       2024-08-30 16:53:50 +08:00
    网站可以发出来看一下吗,我保证不做 sql 注入
    drymonfidelia
        31
    drymonfidelia  
    OP
       2024-08-30 17:00:13 +08:00
    @vvhy
    @CEBBCAT
    @lisongeee
    @adoal
    @tool2dx
    @DOLLOR
    @BugCry 我又没说我在 url 里直接拼 base64 ,是我对接的很多人、接口都在往 url 、cookies 里直接拼接 base64 ,大厂也在这么干。例如你随便打开一个有接入 akamai bot manager 的网站,像 nike.com ,找到 _abck 这个 cookies ,第三段就是直接拼接的 base64
    drymonfidelia
        32
    drymonfidelia  
    OP
       2024-08-30 17:01:05 +08:00
    @drymonfidelia 然后 cookies 就是 key=value 编码的,如果直接按=截断就会出现这个问题
    justseemore
        33
    justseemore  
       2024-08-30 17:01:50 +08:00
    base64 urlsafe
    oamu
        34
    oamu  
       2024-08-30 17:03:19 +08:00
    稍微了解下位运算也不至于说出 “码表长度是 2 的整数次方没有任何的加成。” 这种话。
    proxytoworld
        35
    proxytoworld  
       2024-08-30 17:19:10 +08:00
    @drymonfidelia 你没对=做判断吗,=是最后出现的字符,而且最多两个,这分割没啥大问题啊
    tool2dx
        36
    tool2dx  
       2024-08-30 17:26:29 +08:00
    @drymonfidelia 你标题有没写 cookies ,只说了 url 。

    cookies 内是允许用=符号的,虽然我也觉得解析起来会很奇怪,但浏览器确实是允许的。
    msg7086
        37
    msg7086  
       2024-08-30 17:58:11 +08:00   1
    URL 不适合用 base64 所以有了 base64 的 url-safe 版本。
    Cookie 不是问题吧,本来就是按等号分割成两部分,第二部分有没有等号不影响使用。
    drymonfidelia
        38
    drymonfidelia  
    OP
       2024-08-30 18:10:22 +08:00
    @msg7086 URL 一样是用=分为两部分,只是 cookies 分隔符是=和;,URL 是=和&,没有本质区别我就只写了一个
    @tool2dx
    NoOneNoBody
        39
    NoOneNoBody  
       2024-08-30 18:11:58 +08:00   1
    既然都说的二进制,总应该知道 6 个 bit 就是 64 吧? 62 不能完整表示 6 个 bit 啊,36 表示 5 个 bit 又浪费了几个字符
    这些编码本来就早于 url 诞生的,你应该问的是为什么 url 标准不考虑兼容 base64

    base64 的重要思想是将 bytes 以可视、非控制字符表示,是 bytes 类型转无控制字符的 string 类型的最简单实现,压根就和 url 没什么关系
    cheng6563
        40
    cheng6563  
       2024-08-30 19:10:34 +08:00
    有没有可能就是单纯的 base64 比 url 诞生的早?
    R4rvZ6agNVWr56V0
        41
    R4rvZ6agNVWr56V0  
       2024-08-30 19:15:45 +08:00
    延续 40 楼的发言:
    Base64 最早是在 1993 年由 IETF (互联网工程任务组)定义的。当时,它作为 MIME (多用途互联网邮件扩展)协议的一部分被提出。
    在那之前,互联网主要用于电子邮件和文件传输,但 WWW ( World Wide Web )还处于非常早期的阶段。Base64 并不是专门为 WWW 发明的,但它恰好在 WWW 开始普及之际被标准化。这种巧合使得 Base64 成为 WWW 生态系统中的一个重要工具,为网页中的二进制数据传输提供了可靠的解决方案。
    n18255447846
        42
    n18255447846  
       2024-08-30 19:29:36 +08:00   1
    1. base64 应用广泛
    2. 处理 url 需要 encode/decode
    Terminl
        43
    Terminl  
       2024-08-31 07:46:19 +08:00
    @drymonfidelia 这个还真不是 base64 的锅,完全是你的个人技术问题,图片传输也用 base64,data:image/png;base64,这种多符号的你不是丢失的更多信息?
    iceheart
        44
    iceheart  
       2024-08-31 08:09:59 +08:00 via Android
    k/v 解析只需要处理到第一个分隔符,
    有 bug 改就完了。
    qiumaoyuan
        45
    qiumaoyuan  
       2024-08-31 10:12:25 +08:00
    我把内容一字不漏的复制给了 claude ,得出了和楼上各位差不的回答。
    ShuWei
        46
    ShuWei  
       2024-08-31 10:24:35 +08:00
    会不会是你直接拿=去分割 url 的做法本身就不合理呢
    yianing
        47
    yianing  
       2024-08-31 23:08:34 +08:00
    base64 里有给 url 准备的编码方式,golang 里叫 URLEncoding ,标准的是 StdEncoding
    inza9hi
        48
    inza9hi  
       2024-09-01 10:09:38 +08:00
    @lisongeee 这里比较坑的点是 url 可能被 encoding 多次。
    举例:A 服务返回一个 json ,里面有一个 url B 服务调用 A 服务,返回给客户端,这时候是否要
    lisongeee
        49
    lisongeee  
       2024-09-02 11:50:16 +08:00   1
    @inza9hi

    只要按照使用标准序列化对象解析/构造 url ,无论服务调用多少次都不可能出现这种问题

    但是实际上很多程序员都是半吊子懒狗,都喜欢手动拼接/分割参数,这就容易导致解码/编码时破坏整个 url
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3861 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 10:16 PVG 18:16 LAX 03:16 JFK 06:16
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86