【问题标题】:Corruption of base64-encoded ajax sends -some thoughts on thisbase64 编码的 ajax 损坏发送 - 对此的一些想法
【发布时间】:2013-10-03 02:48:04
【问题描述】:

一直在重新审视为什么某些类型的字符数据在通过 ajax 调用发送到网络服务器时会损坏的问题,无论使用什么编码。即使数据被预编码为 7 位格式,输出的数据仍然不总是等于输入的数据。

我使用第三方 javascript base64 编码器来准备 ajax 数据,并最初认为这有一个错误。但是,其他 base64 编码器显示完全相同的问题——包括一个声称完全兼容 unicode 的问题——并且有几个类似问题的论坛报告,似乎都没有完全解决。所以,我不认为编码器本身有问题。

我注意到,如果数据包含某些特定的高阶 ASCII/ANSI 代码,则通常会在从其他程序剪切并粘贴到 CKEditor 中的数据时出现损坏。

更多测试似乎表明问题与 javascript 从网页读取字符数据的方式与它从内部编程方法形成字符串数据的方式(例如 String.fromCharCode( )。

在下面的 sn-p 中,将通过文本编辑器剪切和粘贴插入 HTML 文档的字符 0x9E 的处理与从十六进制代码 0x9E 以编程方式生成的相同字符(U+017E - Arial Latin small z with caron, Windows Western charset)。这是导致这种异常行为的几个字符代码之一。奇怪的是,大多数其他大于 127 个字符的代码都没有出现这样的问题,而是按照它们应该的方式呈现为两字节 unicode。

<script>
  var pasted_char = 'ž';
  alert("Pasted Character: " + pasted_char + " Resultant Code(s): " + charcodes(pasted_char));

  var charcode = 0x9E;
  var generated_char = String.fromCharCode(charcode);
  alert("Generated Character: " + generated_char + " Resultant Code(s): " + charcodes(generated_char));

function charcodes(invar) {
  // lists char codes for each byte in a character. 
  var ccodes = "~";
  for (ct=0; ct<invar.length; ct++){
    var invarc = invar.charCodeAt(ct);
    ccodes += invarc + "~";
  }
  return ccodes;
}
</script>

使用 UTF-8 页面字符集,给出:

粘贴字符:[0xFFFD] 结果代码:~65533~

生成的字符:[空白] 结果代码:~158~

使用默认页面字符集,给出:

粘贴字符:ž 结果代码:~382~

生成的字符:[空白] 结果代码:~158~

值得注意的是,对粘贴字符的处理都不是正确的,并且没有像 382 这样的 ANSI 代码!

两个输出都是单字节。

严格来说,这个字符是 8 位 ASCII/ANSI,js 并没有声称可以处理它,但是将它粘贴到 HTML 编辑器中是完全合法的,例如从文本文档中。因此,javascript 子系统应该能够处理此类输入而不会出现错误。无论如何,在我看来,以两种不同的方式生成相同的字符串不应该返回两个不同的结果。

欢迎对此提出任何想法。我不确定这个异常在破坏 ajax 发送方面究竟扮演了什么角色,但它似乎很可能是罪魁祸首。

【问题讨论】:

    标签: javascript ajax utf-8 base64


    【解决方案1】:

    JavaScript 中的所有 Strings 都在 UTF-16 中(有时它是前身 USC-2),无论页面的字符编码如何。这在section 8.4 of the ES5 specification 和 ES3 的第 8.5 节中有说明。对于 az 等常见字符,这对您是否需要 ANSIUTF-8 代码影响不大,因为它们是相同的,但是并非所有角色都如此。

    如果你想生成 ANSI,你需要一个 256 项的字典或其他一些用于字符映射的逻辑。


    这是一个这样的表(没有控制字符)

    var ANSI = {
        " ": 32,
        "!": 33,
        "\"": 34,
        "#": 35,
        "$": 36,
        "%": 37,
        "&": 38,
        "'": 39,
        "(": 40,
        ")": 41,
        "*": 42,
        "+": 43,
        ",": 44,
        "-": 45,
        ".": 46,
        "/": 47,
        "0": 48,
        "1": 49,
        "2": 50,
        "3": 51,
        "4": 52,
        "5": 53,
        "6": 54,
        "7": 55,
        "8": 56,
        "9": 57,
        ":": 58,
        ";": 59,
        "<": 60,
        "=": 61,
        ">": 62,
        "?": 63,
        "@": 64,
        "A": 65,
        "B": 66,
        "C": 67,
        "D": 68,
        "E": 69,
        "F": 70,
        "G": 71,
        "H": 72,
        "I": 73,
        "J": 74,
        "K": 75,
        "L": 76,
        "M": 77,
        "N": 78,
        "O": 79,
        "P": 80,
        "Q": 81,
        "R": 82,
        "S": 83,
        "T": 84,
        "U": 85,
        "V": 86,
        "W": 87,
        "X": 88,
        "Y": 89,
        "Z": 90,
        "[": 91,
        "\\": 92,
        "]": 93,
        "^": 94,
        "_": 95,
        "`": 96,
        "a": 97,
        "b": 98,
        "c": 99,
        "d": 100,
        "e": 101,
        "f": 102,
        "g": 103,
        "h": 104,
        "i": 105,
        "j": 106,
        "k": 107,
        "l": 108,
        "m": 109,
        "n": 110,
        "o": 111,
        "p": 112,
        "q": 113,
        "r": 114,
        "s": 115,
        "t": 116,
        "u": 117,
        "v": 118,
        "w": 119,
        "x": 120,
        "y": 121,
        "z": 122,
        "{": 123,
        "|": 124,
        "}": 125,
        "~": 126,
        " ": 127,
        "€": 128,
        " ": 129,
        "‚": 130,
        "ƒ": 131,
        "„": 132,
        "…": 133,
        "†": 134,
        "‡": 135,
        "ˆ": 136,
        "‰": 137,
        "Š": 138,
        "‹": 139,
        "Œ": 140,
        " ": 141,
        "Ž": 142,
        "«": 143,
        " ": 144,
        "‘": 145,
        "’": 146,
        "“": 147,
        "”": 148,
        "•": 149,
        "–": 150,
        "—": 151,
        "˜": 152,
        "™": 153,
        "š": 154,
        "›": 155,
        "œ": 156,
        " ": 157,
        "ž": 158,
        "Ÿ": 159,
        " ": 160,
        "¡": 161,
        "¢": 162,
        "£": 163,
        "¤": 164,
        "¥": 165,
        "¦": 166,
        "§": 167,
        "¨": 168,
        "©": 169,
        "ª": 170,
        "«": 171,
        "¬": 172,
        "­": 173,
        "®": 174,
        "¯": 175,
        "°": 176,
        "±": 177,
        "²": 178,
        "³": 179,
        "´": 180,
        "µ": 181,
        "¶": 182,
        "·": 183,
        "¸": 184,
        "¹": 185,
        "º": 186,
        "»": 187,
        "¼": 188,
        "½": 189,
        "¾": 190,
        "¿": 191,
        "À": 192,
        "Á": 193,
        "Â": 194,
        "Ã": 195,
        "Ä": 196,
        "Å": 197,
        "Æ": 198,
        "Ç": 199,
        "È": 200,
        "É": 201,
        "Ê": 202,
        "Ë": 203,
        "Ì": 204,
        "Í": 205,
        "Î": 206,
        "Ï": 207,
        "Ð": 208,
        "Ñ": 209,
        "Ò": 210,
        "Ó": 211,
        "Ô": 212,
        "Õ": 213,
        "Ö": 214,
        "×": 215,
        "Ø": 216,
        "Ù": 217,
        "Ú": 218,
        "Û": 219,
        "Ü": 220,
        "Ý": 221,
        "Þ": 222,
        "ß": 223,
        "à": 224,
        "á": 225,
        "â": 226,
        "ã": 227,
        "ä": 228,
        "å": 229,
        "æ": 230,
        "ç": 231,
        "è": 232,
        "é": 233,
        "ê": 234,
        "ë": 235,
        "ì": 236,
        "í": 237,
        "î": 238,
        "ï": 239,
        "ð": 240,
        "ñ": 241,
        "ò": 242,
        "ó": 243,
        "ô": 244,
        "õ": 245,
        "ö": 246,
        "÷": 247,
        "ø": 248,
        "ù": 249,
        "ú": 250,
        "û": 251,
        "ü": 252,
        "ý": 253,
        "þ": 254,
        "ÿ": 255
    };
    

    我使用以下代码生成了这个,应用于this page,并复制并粘贴到这里,做了一些非常小的修改(\" 上的转义),所以你会注意到一些字符没有正确交叉(特别是不同类型的空间),并且可能需要先删除/删除/修改才能使用它。您可能还想为键切换到字符编码安全 \uXXXXformat。

    var cells = document.getElementsByTagName('table')[0].getElementsByTagName('td'),
        a = [], i, j, k, v;
    for (j = 0; j < 7; ++j) for (i = 7 + j; i < cells.length; i += 7) {
        k = cells[i].textContent.slice(-1);
        v = +cells[i].textContent.slice(0, 3).replace(/[^\d]/g, '');
        a.push('    "' + k + '": ' + v);
    }
    '{\n' + a.join(',\n') + '\n}';
    

    【讨论】:

    • 我认为您错过了重点,即 javascript 以异常方式处理剪切和粘贴文本中的某些特定字符,并输出废话而不是正确的 UTF 代码。无论字符集如何,这都不应该发生。
    • @IanR 我的意思是;一旦被浏览器解释,142 处的 ANSI ž 变为 382 处的 UTF-16 ž。一旦你粘贴它,它立即变成382 - 它曾经是142 被遗忘。 String.fromCharCode(382); // "ž"
    • @IanR 在字典中进行了编辑,例如我所说的创建,但请阅读 cmets 的相关信息
    • 我不明白单字节字符代码如何具有 382 的值。当然,一个 UTF 字符应该由一个或多个从 0 到 0xFF 的值组成? charCodeAt(ct) 似乎可以正确返回其他 unicode 数据的两个或四个字节。
    • S:“关键是,在 UTF-16 中,ž 不是单个字节”-我知道这一点。不幸的是,意识到这一点并不能解决某些特定字符的 base64 编码会导致错误数据的问题。看起来这个问题可以通过在 base64 编码之前对整个数据进行十六进制字符串编码来解决,但这是非常低效的。我想知道是否可以可靠地检测到这些(相对较少且晦涩的)问题字符,如果可以的话,简单地剥离它们是可以接受的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-20
    • 2015-08-13
    相关资源
    最近更新 更多