Base64与国际化

本文介绍了Base64编码的原理、应用场景,特别是在处理包含非ASCII字符的国际化问题中的作用。当HTTP头部信息包含非ASCII字符时,Base64编码可以将这些字符转换为ASCII兼容的格式,确保数据的正确传输。同时,文章提醒,Base64编码不适用于数据加密或校验,只是一种数据编码手段。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

背景介绍

抛个问题,什么是base64?何时会用到他?与我们熟知的charset又是怎样的关系呢?跟国际化又有何恩怨呢?先看看wikipedia对其定义吧。

Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于 26=64,所以每6个比特为一个单元,对应某个可打印字符。3个字节有24个比特,对应于4个Base64单元,即3个字节可由4个可打印字符来表示。它可用来作为电子邮件的传输编码。在Base64中的可打印字符包括字母A-Z、a-z、数字0-9,这样共有62个字符,此外两个可打印符号在不同的系统中而不同。

Base64常用于在通常处理文本数据的场合,表示、传输、存储一些二进制数据,包括MIME的电子邮件及XML的一些复杂数据。

编码原理

之所以称为Base64,是因为其使用64个字符来对任意数据进行编码,同理有Base32、Base16编码。标准Base64编码使用的64个字符为:

 

这64个字符是各种字符编码(比如ASCII编码)所使用字符的子集,基本,并且可打印。唯一有点特殊的是最后两个字符,因对最后两个字符的选择不同,Base64编码又有很多变种,比如Base64 URL编码。

具体算法可以细分为如下步骤。

  1. 获取字符的UTF8对应编码,转化为对应的24位二进串
  2. 将这24个的二进制串分成4组,每组6个
  3. 在每组前添加两个0,扩展成32位二进制串
  4. 分组获取二进制对应的数字
  5. 查表获得每个值对应Base64编码

用中文举例,“中”字对应的UTF-8编码为E4 B8 AD,转化为二进制是三字节的11100100 10111000 10101101。将这个24位的二进制串,转换成四组32位的二进制值00111001 00001011 00100010 00101101,他们对应的十进制数字为57 11 34 45,通过查表我们就可以知道“中”字对应base64就是5Lit。

若原数据长度不是3的倍数时且剩下1个输入数据,则在编码结果后加2个=;若剩下2个输入数据,则在编码结果后加1个=。标准Base64编码通常用=来替换最后的A,即编码结果为 SGVsbG8hIQ==。因为= 并不在Base64编码索引表中,其意义在于结束符号,在Base64解码时遇到=时即可知道一个Base64编码字符串结束。

场景应用

  • 对图片进行编码

在前端的世界里,对于一些简单图片,通常会选择将内容直接内嵌在页面中,避免不必要的资源加载。而一旦图片是二进制数据,就需要用到一个叫做Data URLs 的属性,使用Base64对图片或其他文件的二进制数据进行编码,将编码后的为文本字符串嵌入到网页中,如下所示。

<img alt="Embedded Image" src="https://img-blog.csdnimg.cn/2022010709205219735.png" />

  • MIME

发mail使用的SMTP协议最初是基于ASCII文本的,对于二进制文件(包括邮件附件中的图像、声音等)的处理并不好,后来新增MIME标准来编码二进制文件,使其能够通过SMTP协议传输。

看来一封mail的源码。

Content-Type: text/plain; name="hello.txt"

表示附件文件名为 hello.txt ,格式为纯文本。

Content-Transfer-Encoding: base64

表示附件文件内容使用base64编码后传输。

5oKo5aW977yM5LiW55WM77yB

这一串无意义的数字则是文件内容经过Base64编码后的显示结果。

关于完整Base64定义可见RFC 1421和RFC 2045。需要注意编码后的数据比原始数据略长,大概为原来的 1.35倍。

 

不过这些似乎跟国际化都没明显啥关系哦?稍安勿躁,真实案例这就登场。

案例分析

首先在AD中创建一个叫做 卡尔文@xx.com的用户并赋予其管理员权限。接近着用该用户登陆,意外就这样的不请自来了。

该用户未被授权?反复验证后,错误依旧。

从log中我们发现,该用户正在尝试用这样的HTTP header进行authentication。

X-Username: 卡尔文

X-Password: 123456

而错误信息为Unable set request header: X-Username: 卡尔文

 

通过查阅RFC,我们看到了这样的信息。RFC 7230 3.2.4(https://tools.ietf.org/html/rfc7230#section-3.2.4)写到:

Historically, HTTP has allowed field content with text in the ISO-8859-1 charset [ISO-8859-1], supporting other charsets only through use of [RFC2047] encoding. In practice, most HTTP header field values use only a subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD limit their field values to US-ASCII octets. A recipient SHOULD treat other octets in field content (obs-text) as opaque data.

哦~~~原来HTTP header中是无法包含中文信息的,他只能接受ASCII,而一旦用户信息中包含中文、日文这样的foreign character,就需要考虑召唤base64这样的编码规范来单骑救主了。Fix示意代码如下。

public class Base64Test {
          public static String encodeBase64(String value) {
                   if (value == null) {
                             return null;
                   }

                   try {
                             return new String(java.util.Base64.getEncoder().encode(value.getBytes("UTF-8")), "UTF-8");
                   } catch (UnsupportedEncodingException e) {
                             e.printStackTrace();
                             return null;
                   }
          }

          public static String decodeBase64(String value) {
                   if (value == null) {
                             return null;
                   }

                   try {
                             return new String(Base64.getDecoder().decode(value.getBytes("UTF-8")), "UTF-8");
                   } catch (UnsupportedEncodingException e) {
                             e.printStackTrace();
                             return null;
                   }
          }

          public static void replaceWithBase64DecodedHeaders(String value) {
                   System.out.println("Base64DecodedHeader is X-Username: " + encodeBase64(value));

          }

}

打印结果为Base64DecodedHeader is X-Username: 5Y2h5bCU5paH,再次尝试用该中文用户登陆,之前弹出的问题随之烟消云散。

个人总结

不少业务场景下的数据传输要求只能由ASCII字符构成,例如HTTP协议要求请求的首行和请求头都必须是ASCII编码,这种情形下请务必使用base64或类似编码方式进行处理,以绝后患。

注意事项

Base64作为一种数据编码方式,其目的是让数据符合传输协议的要求,万不可用于数据加密或数据校验。因为标准Base64编码解码无需额外信息即完全可逆,即使你自己自定义字符集设计一种类Base64的编码方式用于数据加密,在多数场景下也非常容易破解。

Base64兼顾字符集大小和编码后数据长度,并且可以灵活替换字符集的最后两个字符,以应对多样的需求,使其适用场景非常广泛。当然根据场景不同,我们有多种编码方式可供选择,Base64编码并非唯一。就笔者非常有限的了解来看,Quoted-printable就可作为plan B。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值