为什么 %fd 是 url 解码的无效字符串?

Why is %fd an invalid string for url decoding?

为什么使用 Javascript 中的 decodeURIComponent 解码 %e9 或 %fd 无效字符串?

这些字符出现在字符串的中间,我无法理解问题出在哪里。它们是有效的十六进制字符。

完整字符串(这是客户端应用程序发送到服务器的字符串的一部分,被 modsec 阻止):

%61%e9%3d%36%7f%00%00%01%00%00%43%fd%a1%5a%00%00%00%43

解码样本:

decodeURIComponent("%61%e9%3d%36%7f%00%00%01%00%00%43%fd%a1%5a%00%00%00%43")

错误:

VM222:1 Uncaught URIError: URI malformed
    at decodeURIComponent (<anonymous>)
    at <anonymous>:1:1

我正在使用这两个函数对 base64 进行编码并从 base64 进行解码(来自此处:Mozilla):

function c64(t) {
        return btoa(encodeURIComponent(t).replace(/%([0-9A-F]{2})/g,
                (match, p1) => {
            return String.fromCharCode('0x' + p1);
        }));
    }

function d64(t) {
        return decodeURIComponent(atob(t).split('').map(function (c) {
            return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
        }).join(''));
    }

原始字符串是base64:

d64("Yek9Nn8AAAEAAEP9oVoAAABDYek9Nn8AAAEAAEP9oVoAAABD")

returns:

...js:1 Uncaught URIError: URI malformed
    at decodeURIComponent (<anonymous>)

这是因为该字符在十六进制编码中的 unicode 表示不是 "%e9""%E9"

首先在控制台中输入: "\u00e9""\u00E9"

在您的示例中被 "\u00" 替换为 %。您将获得:

'é'

您可以通过 运行ning 验证:

escape('é') //"%E9".

现在运行

encodeURIComponent('é')

你会得到 "%C3%A9" 而不是 "%E9"。这是因为 encodeURIComponent returns 字节的十六进制转储。如果字符是 2 个字节,你得到 %xx%yy,如果是 3 个字节,你得到 %xx%yy%zz.

"€" 试试这个。首先做:

escape("€")

,你将得到 '%u20AC' 或与 "\u20AC" 相同。

获取其字节码的十六进制转储运行:

encodeURIComponent("€") 你会得到 '%E2%82%AC'.

This example from Wikipedia 'UTF-8' article详细解释了'%E2%82%AC'是如何计算的。它是 11100010 10000010 10101100.

的十六进制转储