如何在 JavaScript 中使用字节数组将字符串转换为 base64 编码?

Posted

技术标签:

【中文标题】如何在 JavaScript 中使用字节数组将字符串转换为 base64 编码?【英文标题】:How to convert a string to base64 encoding using byte array in JavaScript? 【发布时间】:2019-08-16 18:51:01 【问题描述】:

我有下面的 .NET 代码通过首先将字符串转换为字节数组来将字符串转换为 Base64 编码。我在 Stack Overflow 上尝试了不同的答案来转换字节数组中的字符串,然后使用 btoa() 函数在 javascript 中进行 base64 编码。但是,我没有得到下面共享的确切编码值。

对于字符串值,

BBFDC43D-4890-4558-BB89-50D802014A97

我需要Base64编码,

PcT9u5BIWEW7iVDYAgFKlw==

.NET 代码:

String str = "BBFDC43D-4890-4558-BB89-50D802014A97"
Guid guid = new Guid(str);
Console.WriteLine(guid);    // bbfdc43d-4890-4558-bb89-50d802014a97
Byte[] bytes = guid.ToByteArray();
Console.WriteLine(bytes);   // System.Byte[]
String s = Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
Console.WriteLine(s);   // PcT9u5BIWEW7iVDYAgFKlw==

目前,我尝试使用以下代码,但没有产生预期的结果:

function strToUtf8Bytes(str) 
  const utf8 = [];
  for (let ii = 0; ii < str.length; ii++) 
    let charCode = str.charCodeAt(ii);
    if (charCode < 0x80) utf8.push(charCode);
    else if (charCode < 0x800) 
      utf8.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f));
     else if (charCode < 0xd800 || charCode >= 0xe000) 
      utf8.push(0xe0 | (charCode >> 12), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));
     else 
      ii++;
      // Surrogate pair:
      // UTF-16 encodes 0x10000-0x10FFFF by subtracting 0x10000 and
      // splitting the 20 bits of 0x0-0xFFFFF into two halves
      charCode = 0x10000 + (((charCode & 0x3ff) << 10) | (str.charCodeAt(ii) & 0x3ff));
      utf8.push(
        0xf0 | (charCode >> 18),
        0x80 | ((charCode >> 12) & 0x3f),
        0x80 | ((charCode >> 6) & 0x3f),
        0x80 | (charCode & 0x3f),
      );
    
  
  return utf8;


const str = "BBFDC43D-4890-4558-BB89-50D802014A97";
const strByteArr = strToUtf8Bytes(str);
const strBase64 = btoa(strByteArr);
// NjYsNjYsNzAsNjgsNjcsNTIsNTEsNjgsNDUsNTIsNTYsNTcsNDgsNDUsNTIsNTMsNTMsNTYsNDUsNjYsNjYsNTYsNTcsNDUsNTMsNDgsNjgsNTYsNDgsNTAsNDgsNDksNTIsNjUsNTcsNTU=

【问题讨论】:

能否也提供你使用的JS代码? 可能重复来自:***.com/questions/246801/… 这不是那个问题的重复,因为我正在使用 btoa() 进行编码,但我担心这里的字节数组。 您确定 PcT9u5BIWEW7iVDYAgFKlw== 是字符串 BBFDC43D-4890-4558-BB89-50D802014A97 的 base64 表示形式 您应该发布您的 javascript 代码。同样,正如我之前所说,您的代码不会将该字符串转换为 base64,而是将该字符串作为一组十六进制值,将其转换为以 10 为基数,然后将生成的字节数组编码为以 64 为基数 【参考方案1】:

您的问题是由以下原因引起的:

btoa() 使用 ASCII 编码 guid.ToByteArray(); 不使用 ASCII 编码

如果你像这样修改你的 C# 代码:

String str = "BBFDC43D-4890-4558-BB89-50D802014A97";
//Guid guid = new Guid(str);
//Console.WriteLine(guid);
// bbfdc43d-4890-4558-bb89-50d802014a97
//Byte[] bytes = guid.ToByteArray();
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(str);
//Console.WriteLine(bytes);   // System.Byte[]
String s = Convert.ToBase64String(bytes, Base64FormattingOptions.InsertLineBreaks);
Console.WriteLine(s);

你会得到以下输出:

QkJGREM0M0QtNDg5MC00NTU4LUJCODktNTBEODAyMDE0QTk3

btoa() 函数返回的字符串相同:

var rawString = "BBFDC43D-4890-4558-BB89-50D802014A97";
var b64encoded = btoa(rawString);
console.log(b64encoded);

输出:

QkJGREM0M0QtNDg5MC00NTU4LUJCODktNTBEODAyMDE0QTk3

更新 - 由于您无法修改 C# 代码

您应该通过组合 Piotr's answer 和 this SO answer 来调整您的 Javascript 代码

function guidToBytes(guid) 
    var bytes = [];
    guid.split('-').map((number, index) => 
        var bytesInChar = index < 3 ? number.match(/.1,2/g).reverse() : number.match(/.1,2/g);
        bytesInChar.map((byte) =>  bytes.push(parseInt(byte, 16)); )
    );
    return bytes;


function arrayBufferToBase64(buffer) 
    var binary = '';
    var bytes = new Uint8Array(buffer);
    var len = bytes.byteLength;
    for (var i = 0; i < len; i++) 
        binary += String.fromCharCode(bytes[i]);
    
    return btoa(binary);


var str = "BBFDC43D-4890-4558-BB89-50D802014A97";
var guidBytes = guidToBytes(str);
var b64encoded = arrayBufferToBase64(guidBytes);
console.log(b64encoded);

输出:

PcT9u5BIWEW7iVDYAgFKlw==

【讨论】:

ASCII 或 UTF8 在这里没有区别,因为在代码点 127 之前它们是相同的。 @marko 我无法更改 .NET 代码,因为它是旧代码。我只需要在 JS 中复制它。 @HimanshuAggarwal 我刚刚用您需要进行的 Javascript 修改更新了答案。 我一直在尝试扭转这种情况以根据需要倒退,但无法到达那里,有什么关于转换回来的建议吗?【参考方案2】:

您的代码的问题在于 Guid 的表示。在 C# 代码中,您将“BBFDC43D-4890-4558-BB89-50D802014A97”转换为 128 位数字的 UUID。在 JavaScript 代码中,您正在做其他事情。您遍历字符串并计算字符串的字节数组。他们根本就不平等。 现在你必须选择

    在 JS 中实现正确的 guid 转换(这可能会有所帮助:https://gist.github.com/daboxu/4f1dd0a254326ac2361f8e78f89e97ae) 在 C# 中计算字节数组的方法与在 JS 中相同

【讨论】:

【参考方案3】:

您的字符串是一个十六进制值,用于创建 GUID。然后将 GUID 转换为字节数组:

Byte[] bytes = guid.ToByteArray();

GUID 是一个 16 字节的值,可以表示为十六进制值。当您将此 GUID 转换为字节数组时,您将获得 16 个字节的值,不是十六进制值的字节表示。

在提供的 JavaScript 函数中,您正在执行其他操作:您正在将字符串 直接 转换为字节数组。

在 C# 中,您可以使用 Encoding

String str = "BBFDC43D-4890-4558-BB89-50D802014A97";
Byte[] bytes = Encoding.UTF8.GetBytes(str);

【讨论】:

以上是关于如何在 JavaScript 中使用字节数组将字符串转换为 base64 编码?的主要内容,如果未能解决你的问题,请参考以下文章

如何仅使用 javascript 将图像转换为字节数组以将图像存储在 sql server 上?

如何将javascript中uint8array转成普通数组或字符串?

如何将javascript中uint8array转成普通数组或字符串

如何将十六进制字符串转换为字节数组? [复制]

如何将字符串转换为字节数组? [关闭]

如何将字节数组的字符串转换为字节数组