是否有 Javascript 等同于 urllib.quote 和 urllib.unquote?

Is there a Javascript equivalent to urllib.quote and urllib.unquote?

根据这个 answer 几年前给出的相同问题,Javascript 中的 encodeURIComponent(str) 应该等同于 urllib.quote(str, safe='~() *!.\'') Python。通过扩展,我猜到 decodeURIComponent(str) 将等同于 urllib.unquote(str).

根据我的经验,情况并非如此。我正在编写一些网络代码以从 Python 服务器与网站上的客户端进行通信,但我得到了不同的结果。

我正在生成一个唯一 ID 并使用与以下代码几乎相同的内容通过 TCP 发送它:

import urllib
import struct
import random

def sendID():
    id = random.SystemRandom().getrandbits(128)
    upper = id >> 64
    lower = id & 0xFFFFFFFFFFFFFFFF
    packed = struct.pack('<B2Q', 0x00, upper, lower)
    encoded = urllib.quote(packed, safe='~()*!.\'')

    # the below line is just sending it over an already established TCP connection
    # the code is irrelevant as I already this is working as expected
    sendtoclient(encoded)

客户端在以下 websocket 对象回调中收到消息:

this.websocket.onmessage = function (msg) {
    console.log(msg.data);
    var sType = bufferpack.unpack('<B', decodeURIComponent(msg.data).substring(0, 1));
    console.log(sType);
};

这应该解码 msg.data 字符串并将 sType 设置为打包数据的第一个 'part'(在本例中为 0x00)。

我遇到的问题是这些功能没有按我的预期运行。在 JSFiddle 和 Python 命令行中进行一些测试后,我得到了 encode/decodeURIComponent 和 urllib.quote/unquote 函数的不同结果。 encodeURIComponent 只是给我一个与 'equivalent' urllib.quote 不同的结果,而 decodeURIComponent 导致格式错误的 URI 错误。

这可以在下面显示的示例中看到:

>>> import random
>>> import urllib
>>> import struct

>>> id = random.SystemRandom().getrandbits(128)
>>> upper = id >> 64
>>> lower = id & 0xFFFFFFFFFFFFFFFF
>>> packed = struct.pack('<B2Q', 0x00, upper, lower)
>>> encoded = urllib.quote(packed, safe='~()*!.\'')

>>> id
79837607446780471980532690349264559028L
>>> upper
4328005371992213727L
>>> lower
4092443888854326196L
>>> packed
'\x00\xdf\x08\x94\x7f\xf4)\x10<\xb4[a\xc2\x08H\xcb8'
>>> encoded
'%00%DF%08%94%7F%F4)%10%3C%B4%5Ba%C2%08H%CB8'

然而,当我分别在 'packed' 和 'encoded' 上使用 encodeURIComponent 和 decodeURIComponent 时,我得到了不同的编码值并且解码会引发错误。 Javascript 后面的输出如下所示。

console.log(encodeURIComponent('\x00\xdf\x08\x94\x7f\xf4)\x10<\xb4[a\xc2\x08H\xcb8'))
console.log(decodeURIComponent('%00%DF%08%94%7F%F4)%10%3C%B4%5Ba%C2%08H%CB8'));

%00%C3%9F%08%C2%94%7F%C3%B4)%10%3C%C2%B4%5Ba%C3%82%08H%C3%8B8 (index):50 Uncaught URIError: URI malformed

JSFiddle snippet with the above Javascript code for your convenience.

所以最后,我的实际问题是:上面使用的函数(quote/unquote 和 encode/decodeURIComponent)实际上是等价的吗?如果不能,有人可以建议代码更改或其他 libraries/functions 可以达到我的预期(客户端和服务器端的 encoded/decoded 和 packed/unpacked 值相同)?

在使用我的示例代码并阅读了一些关于类似问题的其他资源后,我发现 'packed' 字符串是使用 'latin-1' 字符集编码的,并且 urllib.quote无法正常工作。

下面我从我的 python 解释器中包含了相同的示例,并添加了一些额外的行,表明通过正确的编码函数 urllib.quote/unquote 和 encode/decodeURIComponent 实际上是处理 utf-8 时等效。

>>> import random
>>> import urllib
>>> import struct

>>> id = random.SystemRandom().getrandbits(128)
>>> upper = id >> 64
>>> lower = id & 0xFFFFFFFFFFFFFFFF
>>> packed = struct.pack('<B2Q', 0x00, upper, lower)
>>> encoded = urllib.quote(packed, safe='~()*!.\'')

>>> id
79837607446780471980532690349264559028L
>>> upper
4328005371992213727L
>>> lower
4092443888854326196L
>>> packed
'\x00\xdf\x08\x94\x7f\xf4)\x10<\xb4[a\xc2\x08H\xcb8'
>>> encoded
'%00%DF%08%94%7F%F4)%10%3C%B4%5Ba%C2%08H%CB8'

>>> packed.decode('latin-1')
u'\x00\xdf\x08\x94\x7f\xf4)\x10<\xb4[a\xc2\x08H\xcb8'
>>> packed.decode('latin-1').encode('utf-8')
'\x00\xc3\x9f\x08\xc2\x94\x7f\xc3\xb4)\x10<\xc2\xb4[a\xc3\x82\x08H\xc3\x8b8'
>>> urllib.quote(packed.decode('latin-1').encode('utf-8'), safe='~()*!.\'')
'%00%C3%9F%08%C2%94%7F%C3%B4)%10%3C%C2%B4%5Ba%C3%82%08H%C3%8B8'

输出

'%00%C3%9F%08%C2%94%7F%C3%B4)%10%3C%C2%B4%5Ba%C3%82%08H%C3%8B8'

匹配

的输出

encodeURIComponent('\x00\xdf\x08\x94\x7f\xf4)\x10<\xb4[a\xc2\x08H\xcb8')

在 Javascript.