NJS 中的 Base64 编解码:atob() 与 btoa() 全解析
手机扫码查看
一、atob()/btoa() 核心定位
atob() 和 btoa() 是 NJS 实现 Base64 编解码的原生方法,完全兼容 Web API 标准,核心作用:
- btoa():将二进制字符串编码为 Base64 格式的 ASCII 字符串,解决特殊字符(如 ASCII 0-31 控制字符)传输时的兼容性问题;
- atob():将 Base64 编码的字符串解码为原始二进制字符串,还原编码前的数据。
核心特点:轻量无依赖、执行效率高,仅处理字符串类型数据,是 NGINX 网关层(如请求参数解码、响应数据编码)的首选方案。
二、核心方法详解
2.1 btoa():Base64 编码
语法
btoa(stringToEncode)
| 参数 | 类型 | 说明 |
|---|---|---|
stringToEncode |
二进制字符串 | 待编码的原始字符串(可包含 ASCII 0-31 控制字符) |
| 返回值 | ASCII 字符串 | Base64 编码后的结果,仅包含 Base64 字符集(A-Z、a-z、0-9、+、/、=) |
基础示例
// 普通字符串编码
const rawStr = "text to encode";
const encodedStr = btoa(rawStr);
console.log(encodedStr); // 输出:dGV4dCB0byBlbmNvZGU=
// 包含控制字符的字符串编码(ASCII 0 为 null 字符)
const controlStr = "hello" + String.fromCharCode(0) + "world";
const encodedControlStr = btoa(controlStr);
console.log(encodedControlStr); // 输出:aGVsbG8Ad29ybGQ=
2.2 atob():Base64 解码
语法
atob(encodedData)
| 参数 | 类型 | 说明 |
|---|---|---|
encodedData |
ASCII 字符串 | Base64 编码后的字符串 |
| 返回值 | 二进制字符串 | 解码后的原始字符串,还原编码前的所有字符(包括控制字符) |
基础示例
// 解码普通字符串
const encodedStr = "dGV4dCB0byBlbmNvZGU=";
const decodedStr = atob(encodedStr);
console.log(decodedStr); // 输出:text to encode
// 解码包含控制字符的字符串
const encodedControlStr = "aGVsbG8Ad29ybGQ=";
const decodedControlStr = atob(encodedControlStr);
console.log(decodedControlStr); // 输出:hello\u0000world(\u0000 为 ASCII 0 字符)
2.3 编解码完整流程
// 封装编解码工具函数
function base64Encode(r, rawData) {
try {
return btoa(rawData);
} catch (e) {
r.error(`Base64 编码失败:${e.message}`);
return null;
}
}
function base64Decode(r, encodedData) {
try {
return atob(encodedData);
} catch (e) {
r.error(`Base64 解码失败:${e.message}`);
return null;
}
}
// 使用示例
function handleEncodeDecode(r) {
const raw = "NGINX NJS Base64 Demo";
const encoded = base64Encode(r, raw);
const decoded = base64Decode(r, encoded);
r.log(`原始数据:${raw}`);
r.log(`编码后:${encoded}`); // TkdJTlggTkpTIEJhc2U2NCBEZW1v
r.log(`解码后:${decoded}`); // NGINX NJS Base64 Demo
r.return(200, `编码结果:${encoded}\n解码结果:${decoded}`);
}
三、实战场景:NJS 网关层的编解码应用
3.1 场景1:解码请求头中的 Base64 认证信息
HTTP Basic 认证的 Authorization 头格式为 Basic <Base64编码的用户名:密码>,可通过 atob() 解码获取原始凭证:
# NGINX 配置
http {
js_import auth.js;
server {
listen 80;
location /api {
js_access auth.verifyBasicAuth; # 访问前校验认证
proxy_pass http://backend;
}
}
}
// auth.js
function verifyBasicAuth(r) {
// 获取 Authorization 头
const authHeader = r.headersIn.Authorization;
if (!authHeader || !authHeader.startsWith("Basic ")) {
r.return(401, "未授权:缺少 Basic 认证信息");
return;
}
// 提取 Base64 编码部分并解码
const encodedCreds = authHeader.slice(6); // 去掉 "Basic " 前缀
const decodedCreds = atob(encodedCreds);
const [username, password] = decodedCreds.split(":");
// 校验凭证(实际场景应从配置/数据库获取)
const validUser = "admin";
const validPwd = "123456";
if (username === validUser && password === validPwd) {
r.log(`用户 ${username} 认证通过`);
r.next(); // 放行请求
} else {
r.warn(`用户 ${username} 认证失败`);
r.return(401, "认证失败:用户名或密码错误");
}
}
export default { verifyBasicAuth };
3.2 场景2:编码响应数据中的特殊字符
当响应包含不可打印字符(如 ASCII 控制字符、特殊符号)时,通过 btoa() 编码后传输,客户端再解码:
# NGINX 配置
http {
js_import encode.js;
server {
listen 80;
location /data {
js_content encode.specialCharEncode;
}
}
}
// encode.js
function specialCharEncode(r) {
// 模拟包含控制字符和特殊符号的原始数据
const rawData = {
id: 1001,
content: "核心数据\u0007\u0010", // \u0007(响铃)、\u0010(数据链路转义)
timestamp: new Date().toISOString()
};
// 序列化并编码
const jsonStr = JSON.stringify(rawData);
const encodedData = btoa(jsonStr);
// 设置响应头,告知客户端需解码
r.headersOut['Content-Type'] = 'text/plain';
r.headersOut['X-Data-Encoding'] = 'base64';
// 返回编码后的数据
r.return(200, encodedData);
}
export default { specialCharEncode };
3.3 场景3:编解码 URL 参数中的特殊字符
URL 参数不支持部分特殊字符(如 /、+、=),可通过 Base64 编码避免参数解析错误:
// 处理 URL 参数编解码
function handleParamEncode(r) {
// 读取客户端传入的 Base64 编码参数
const encodedParam = r.args.data || "";
if (!encodedParam) {
r.return(400, "缺少 data 参数(Base64 编码)");
return;
}
// 解码参数
const decodedParam = atob(encodedParam);
r.log(`解码后的参数:${decodedParam}`);
// 处理参数(示例:提取包含特殊字符的路径)
const path = decodedParam;
r.internalRedirect(path); // 内部重定向到解码后的路径
}
四、注意事项与常见问题
4.1 字符编码限制
btoa()仅支持 二进制字符串(即每个字符的 Unicode 码点 ≤ 255),若传入包含多字节 Unicode 字符(如中文、emoji)的字符串,会抛出错误:// 错误示例:包含中文(Unicode 码点 > 255) btoa("中文"); // 抛出 DOMException: The string to be encoded contains characters outside of the Latin1 range.- 解决方法:先将多字节字符串转换为 UTF-8 二进制字符串,再编码(NJS 可通过
Buffer辅助转换):// 兼容多字节字符的编解码 function utf8ToBase64(str) { // 将字符串转换为 UTF-8 Buffer,再转为二进制字符串 const buffer = Buffer.from(str, 'utf8'); const binaryStr = String.fromCharCode(...new Uint8Array(buffer)); return btoa(binaryStr); } function base64ToUtf8(encoded) { const binaryStr = atob(encoded); const buffer = new Uint8Array(binaryStr.split('').map(c => c.charCodeAt(0))); return Buffer.from(buffer).toString('utf8'); } // 使用示例 const chineseStr = "NJS 中文测试"; const encoded = utf8ToBase64(chineseStr); // TkpTIOi2veWbveS6rOmDveivlQ== const decoded = base64ToUtf8(encoded); // NJS 中文测试
4.2 错误处理
- 传入无效 Base64 字符串(如包含非 Base64 字符、长度不是 4 的倍数)时,
atob()会抛出异常; - 编码空字符串时,
btoa()返回空字符串,不会报错; - 建议始终用
try/catch包裹编解码逻辑,避免脚本崩溃。
4.3 性能考量
atob()/btoa()是原生方法,执行效率远高于自定义 Base64 实现;- 避免对超大字符串(如 MB 级)频繁编解码,建议在后端处理,NJS 仅处理轻量级数据(如认证信息、短参数)。
五、总结
- NJS 内置的
atob()/btoa()是轻量高效的 Base64 编解码工具,兼容 Web API 标准,无需依赖第三方模块; btoa()用于将二进制字符串编码为 Base64 ASCII 字符串,atob()用于反向解码,核心解决特殊字符传输问题;- 典型应用场景包括认证头解码、特殊字符参数处理、响应数据编码,需注意多字节字符(如中文)的兼容处理;
- 使用时需通过
try/catch捕获异常,避免无效编码/解码导致请求处理失败。
书签篮