javascript - 无法在 'btoa' : The string to be encoded contains characters outside of the Latin1 range. 上执行 'Window'

标签 javascript google-chrome

根据我的测试,标题中的错误仅在谷歌浏览器中抛出。我正在对一个大的 XML 文件进行 base64 编码,以便可以下载它:

this.loader.src = "data:application/x-forcedownload;base64,"+
                  btoa("<?xml version=\"1.0\" encoding=\"utf-8\"?>"
                  +"<"+this.gamesave.tagName+">"
                  +this.xml.firstChild.innerHTML
                  +"</"+this.gamesave.tagName+">");

this.loader 是隐藏的 iframe。

这个错误实际上是一个很大的变化,因为通常情况下,谷歌浏览器会在 btoa 调用时崩溃。 Mozilla Firefox 在这里没有问题,所以问题与浏览器有关。 我不知道文件中有任何奇怪的字符。事实上,我确实相信没有非 ascii 字符。

问: 如何找到有问题的字符并替换它们,以便 Chrome 停止提示?

我尝试使用 Downloadify 启动下载,但它不起作用。它不可靠,不会抛出任何错误以允许调试。

最佳答案

如果您有 UTF8,请使用它(实际上适用于 SVG 源代码),例如:

btoa(unescape(encodeURIComponent(str)))

例子:

 var imgsrc = 'data:image/svg+xml;base64,' + btoa(unescape(encodeURIComponent(markup)));
 var img = new Image(1, 1); // width, height values are optional params 
 img.src = imgsrc;

如果你需要解码 base64,使用这个:

var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);

例子:

var str = "äöüÄÖÜçéèñ";
var b64 = window.btoa(unescape(encodeURIComponent(str)))
console.log(b64);

var str2 = decodeURIComponent(escape(window.atob(b64)));
console.log(str2);

注意:如果您需要让它在 mobile-safari 中工作,您可能需要从 base64 数据中去除所有空白...

function b64_to_utf8( str ) {
    str = str.replace(/\s/g, '');    
    return decodeURIComponent(escape(window.atob( str )));
}

2017 年更新

这个问题又困扰我了。
一个简单的事实是,atob 并不真正处理 UTF8 字符串——它只是 ASCII。
另外,我不会使用像 js-base64 这样的过时软件。
但是 webtoolkit 确实有一个小巧、漂亮且易于维护的实现:

/**
*
*  Base64 encode / decode
*  http://www.webtoolkit.info
*
**/
var Base64 = {

    // private property
    _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="

    // public method for encoding
    , encode: function (input)
    {
        var output = "";
        var chr1, chr2, chr3, enc1, enc2, enc3, enc4;
        var i = 0;

        input = Base64._utf8_encode(input);

        while (i < input.length)
        {
            chr1 = input.charCodeAt(i++);
            chr2 = input.charCodeAt(i++);
            chr3 = input.charCodeAt(i++);

            enc1 = chr1 >> 2;
            enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
            enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
            enc4 = chr3 & 63;

            if (isNaN(chr2))
            {
                enc3 = enc4 = 64;
            }
            else if (isNaN(chr3))
            {
                enc4 = 64;
            }

            output = output +
                this._keyStr.charAt(enc1) + this._keyStr.charAt(enc2) +
                this._keyStr.charAt(enc3) + this._keyStr.charAt(enc4);
        } // Whend 

        return output;
    } // End Function encode 


    // public method for decoding
    ,decode: function (input)
    {
        var output = "";
        var chr1, chr2, chr3;
        var enc1, enc2, enc3, enc4;
        var i = 0;

        input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
        while (i < input.length)
        {
            enc1 = this._keyStr.indexOf(input.charAt(i++));
            enc2 = this._keyStr.indexOf(input.charAt(i++));
            enc3 = this._keyStr.indexOf(input.charAt(i++));
            enc4 = this._keyStr.indexOf(input.charAt(i++));

            chr1 = (enc1 << 2) | (enc2 >> 4);
            chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
            chr3 = ((enc3 & 3) << 6) | enc4;

            output = output + String.fromCharCode(chr1);

            if (enc3 != 64)
            {
                output = output + String.fromCharCode(chr2);
            }

            if (enc4 != 64)
            {
                output = output + String.fromCharCode(chr3);
            }

        } // Whend 

        output = Base64._utf8_decode(output);

        return output;
    } // End Function decode 


    // private method for UTF-8 encoding
    ,_utf8_encode: function (string)
    {
        var utftext = "";
        string = string.replace(/\r\n/g, "\n");

        for (var n = 0; n < string.length; n++)
        {
            var c = string.charCodeAt(n);

            if (c < 128)
            {
                utftext += String.fromCharCode(c);
            }
            else if ((c > 127) && (c < 2048))
            {
                utftext += String.fromCharCode((c >> 6) | 192);
                utftext += String.fromCharCode((c & 63) | 128);
            }
            else
            {
                utftext += String.fromCharCode((c >> 12) | 224);
                utftext += String.fromCharCode(((c >> 6) & 63) | 128);
                utftext += String.fromCharCode((c & 63) | 128);
            }

        } // Next n 

        return utftext;
    } // End Function _utf8_encode 

    // private method for UTF-8 decoding
    ,_utf8_decode: function (utftext)
    {
        var string = "";
        var i = 0;
        var c, c1, c2, c3;
        c = c1 = c2 = 0;

        while (i < utftext.length)
        {
            c = utftext.charCodeAt(i);

            if (c < 128)
            {
                string += String.fromCharCode(c);
                i++;
            }
            else if ((c > 191) && (c < 224))
            {
                c2 = utftext.charCodeAt(i + 1);
                string += String.fromCharCode(((c & 31) << 6) | (c2 & 63));
                i += 2;
            }
            else
            {
                c2 = utftext.charCodeAt(i + 1);
                c3 = utftext.charCodeAt(i + 2);
                string += String.fromCharCode(((c & 15) << 12) | ((c2 & 63) << 6) | (c3 & 63));
                i += 3;
            }

        } // Whend 

        return string;
    } // End Function _utf8_decode 

}

https://www.fileformat.info/info/unicode/utf8.htm

  • For any character equal to or below 127 (hex 0x7F), the UTF-8 representation is one byte. It is just the lowest 7 bits of the full unicode value. This is also the same as the ASCII value.

  • For characters equal to or below 2047 (hex 0x07FF), the UTF-8 representation is spread across two bytes. The first byte will have the two high bits set and the third bit clear (i.e. 0xC2 to 0xDF). The second byte will have the top bit set and the second bit clear (i.e. 0x80 to 0xBF).

  • For all characters equal to or greater than 2048 but less than 65535 (0xFFFF), the UTF-8 representation is spread across three bytes.

关于javascript - 无法在 'btoa' : The string to be encoded contains characters outside of the Latin1 range. 上执行 'Window',我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23223718/

相关文章:

html - 使用 css 重置元素在 Chrome 和 Firefox 中的不同位置

javascript - 使用 Chrome 扩展程序中的 POST 数据创建链接

javascript - 鼠标单击复制 Qooxdoo 标签文本会在 Chrome 中添加相邻标签文本

google-chrome - 较新的 chrome 在使用 haproxy 服务器的 websocket 上失败

javascript - 如何用 D3 对数组求和?

javascript - 如何使用 Javascript 创建文件夹、该文件夹中的文件、压缩文件夹(zip 或 rar 文件)并将其上传到桌面?

javascript - 在 Drupal 6 中实现精美的 CSS/Javascript 导航菜单的最简单方法?

javascript - 有没有办法通过网页/JavaScript 检查是否安装了谷歌浏览器(和默认浏览器),而无需在客户端安装任何东西?

javascript - 使用相对位置和绝对位置时,我的图像消失了

javascript - Google Analytics 'Event Tracking' 对于我在其他网站上点击的下载链接