You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Xpages中Base64编码Vcard特殊字符异常问题求助

解决Base64编码特殊字符(如é)的问题

问题背景

开发生成Base64编码VCard的应用时,遇到特殊字符编码不符合要求的情况:

  • 目标字符串:Zone d'activité
  • 符合VCard要求的正确Base64结果:Wm9uZSBkJ2FjdGl2aXTDqQ==
  • 现有自定义base64_encode脚本生成的错误结果:Wm9uZSBkJ2FjdGl2aXTp

现有脚本代码如下:

function base64_encode (data) {
// http://kevin.vanzonneveld.net
// +   original by: Tyler Akins (http://rumkin.com)
// +   improved by: Bayron Guevara
// +   improved by: Thunder.m
// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// +   bugfixed by: Pellentesque Malesuada
// +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
// +   improved by: Rafał Kukawski (http://kukawski.pl)
// *     example 1: base64_encode('Kevin van Zonneveld');
// *     returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
// mozilla has this native
// - but breaks in 2.0.0.12!
//if (typeof this.window['btoa'] == 'function') {
//    return btoa(data);
//}
var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
ac = 0,
enc = "",
tmp_arr = [];

if (!data) {
return data;
}

do { // pack three octets into four hexets
o1 = data.charCodeAt(i++);
o2 = data.charCodeAt(i++);
o3 = data.charCodeAt(i++);

bits = o1 << 16 | o2 << 8 | o3;

h1 = bits >> 18 & 0x3f;
h2 = bits >> 12 & 0x3f;
h3 = bits >> 6 & 0x3f;
h4 = bits & 0x3f;

// use hexets to index into b64, and append result to encoded string
tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
} while (i < data.length);

enc = tmp_arr.join('');

var r = data.length % 3;

return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);

}

var demo = "Zone d'activité"
var test = base64_encode(demo);
return test;

问题原因

并非Base64不支持特殊字符,而是字符编码不匹配:

  • VCard规范要求Base64编码的内容必须基于UTF-8字节流,比如é在UTF-8中是两个字节0xC3 0xA9
  • 现有脚本使用charCodeAt()获取的是UTF-16编码的单个码点0xE9,直接基于这个码点编码,导致结果与要求不符

解决方案

方案1:使用浏览器原生API(推荐)

原生btoa仅支持ASCII,需先将字符串转换为UTF-8字节序列再编码:

function utf8ToBase64(str) {
  return btoa(unescape(encodeURIComponent(str)));
}

// 测试
const demo = "Zone d'activité";
console.log(utf8ToBase64(demo)); // 输出正确结果:Wm9uZSBkJ2FjdGl2aXTDqQ==

方案2:修改自定义脚本支持UTF-8

先将字符串转换为UTF-8字节数组,再执行Base64编码逻辑:

function base64_encode_utf8(data) {
  const b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  let enc = "";
  let i = 0;
  // 转换字符串为UTF-8字节数组
  const utf8Bytes = [];
  for (const char of data) {
    const code = char.charCodeAt(0);
    if (code < 0x80) {
      utf8Bytes.push(code);
    } else if (code < 0x800) {
      utf8Bytes.push(0xC0 | (code >> 6));
      utf8Bytes.push(0x80 | (code & 0x3F));
    } else if (code < 0x10000) {
      utf8Bytes.push(0xE0 | (code >> 12));
      utf8Bytes.push(0x80 | ((code >> 6) & 0x3F));
      utf8Bytes.push(0x80 | (code & 0x3F));
    }
  }
  // 执行Base64编码
  while (i < utf8Bytes.length) {
    const o1 = utf8Bytes[i++] || 0;
    const o2 = utf8Bytes[i++] || 0;
    const o3 = utf8Bytes[i++] || 0;
    const bits = (o1 << 16) | (o2 << 8) | o3;
    const h1 = (bits >> 18) & 0x3F;
    const h2 = (bits >> 12) & 0x3F;
    const h3 = (bits >> 6) & 0x3F;
    const h4 = bits & 0x3F;
    enc += b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
  }
  const r = utf8Bytes.length % 3;
  return r ? enc.slice(0, r - 3) + '==='.slice(r) : enc;
}

// 测试
const demo = "Zone d'activité";
console.log(base64_encode_utf8(demo)); // 输出正确结果:Wm9uZSBkJ2FjdGl2aXTDqQ==

注意事项

  • 不要手动替换特殊字符,这会破坏原字符串语义,正确做法是统一采用UTF-8编码后再进行Base64编码
  • 确保VCard生成流程中所有文本内容都采用UTF-8编码,符合规范要求

内容的提问来源于stack exchange,提问作者Marc Jonkers

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 18:15:16