• MIM协议与Base64编码


    MIME Protocol  

    1. MIME的全称是"Multipurpose Internet Mail Extensions",中译为"多用途互联网邮件扩展",指的是一系列的电子邮件技术规范,主要包括RFC 2045、RFC 2046、RFC 2047、RFC 4288、RFC 4289和RFC 2077。

    顾名思义,MIME是对传统电子邮件的一个扩展,现在已经成为电子邮件实际上的标准。

    2. 传统的电子邮件是1982年定下技术规范的,文件是RFC 822。

    它的一个重要特点,就是规定电子邮件只能使用ASCII字符。这导致了三个结果:1)非英语字符都不能在电子邮件中使用;2)电子邮件中不能插入二进制文件(如图片);3)电子邮件不能有附件。

    这实际上无法接受的,因此到了1992年,工程师们决定扩展电子邮件的技术规范,提出一系列补充规范,这就是MIME的由来。

    3. 下面是一封传统的电子邮件。

    From: "Tommy Lee" <lee@example.com>
    To: "Jack Zhang" <zhang@example.com>
    Subject: Test
    Date: Wed, 17 May 2000 19:08:29 -0400
    Message-ID: <NDBBIAKOPKHFGPLCODIGIEKBCHAA.lee@example.com>

    Hello World.

    从上面可以看出,这封信的发信人地址是lee@example.com,收信人地址是zhang@example.com,邮件主题是Test,发送时间是2000年5月17日,邮件内容是"Hello World."。

    在结构上,这封信分为三个部分:首先是信件头,然后是一个空行,最后是信件内容。收信人的客户端软件只会显示最后一部分,要查看全信,必须使用"查看原始邮件"功能。

    4. MIME对传统电子邮件的扩展,表现在它在信件头部分添加了几条语句,主要有三条。

    第一条是:

    MIME-Version: 1.0

    这条语句是必须的,而且1.0这个版本值是不变的,即使MIME本身已经升级了好几次。

    有了这条语句,收信端就知道这封信使用了MIME规范。

    第二条是:

    Content-Type: text/plain; charset="ISO-8859-1"

    这一行是极端重要的,它表明传递的信息类型和采用的编码。

    Content-Type表明信息类型,缺省值为" text/plain"。它包含了主要类型(primary type)和次要类型(subtype)两个部分,两者之间用"/"分割。主要类型有9种,分别是application、audio、example、image、message、model、multipart、text、video。

    每一种主要类型下面又有许多种次要类型,常见的有:

    text/plain:纯文本,文件扩展名.txt
    text/html:HTML文本,文件扩展名.htm和.html
    image/jpeg:jpeg格式的图片,文件扩展名.jpg
    image/gif:GIF格式的图片,文件扩展名.gif
    audio/x-wave:WAVE格式的音频,文件扩展名.wav
    audio/mpeg:MP3格式的音频,文件扩展名.mp3
    video/mpeg:MPEG格式的视频,文件扩展名.mpg
    application/zip:PK-ZIP格式的压缩文件,文件扩展名.zip

    详细的Content-Type列表,可以查看这里这里

    如果信息的主要类型是"text",那么还必须指明编码类型"charset",缺省值是ASCII,其他可能值有"ISO-8859-1"、"UTF-8"、"GB2312"等等。

    整个Content-Type这一行,不仅使用在电子邮件,后来也被移植到了HTTP协议中,所以现在只要是在网上传播的HTTP信息,都带有Content-Type头,以表明信息类型。

    第三条是:

    Content-transfer-encoding: base64

    这条语句指明了编码转换的方式。Content-transfer-encoding的值有5种----"7bit"、"8bit"、"binary"、"quoted-printable"和"base64"----其中"7bit"是缺省值,即不用转化的ASCII字符。真正常用是"quoted-printable"和"base64"两种,它们的详细用法,后面会有介绍。

    5. 下面是一封我收到的邮件的源码:

    复制代码
    Date: Wed, 18 Jun 2008 18:07:51 +0800 (CST)
    From: xxx <xxx@163.com>
    To: yifeng.ruan@gmail.com
    Message-ID: <14410503.1073611213783671983.JavaMail.coremail@bj163app54.163.com>
    Subject: =?gbk?B?xOO6ww==?=
    MIME-Version: 1.0
    Content-Type: multipart/alternative; 
    boundary=&quot;----=_Part_287491_22998031.1213783671982&quot;
    
    ------=_Part_287491_22998031.1213783671982
    Content-Type: text/plain; charset=gbk
    Content-Transfer-Encoding: base64
    
    IAq4+b7dsr+209PQudi55raoo6yyu7XD1Nq12Le9yM66zs341b7Jz7nSz+DTprXEtqvO96Osx+vE
    49TaxOO1xLKpv83W0AogIArW0Ln6yr2x6tPvIC0gyO7Su7fltcTN+MLnyNXWvgoKtcS12jEy1cXN
    vMasyb6z/aOst/HU8s7Sw8fXt76/xOO1xM/gudjU8MjOoaPQu9C7us/X96OhtMvNvMas1Nq4vbz+
    wO/D5g==
    ------=_Part_287491_22998031.1213783671982
    Content-Type: text/html; charset=gbk
    Content-Transfer-Encoding: quoted-printable
    
    <DIV>&amp;nbsp;</DIV>
    <DIV>=B8=F9=BE=DD=B2=BF=B6=D3=D3=D0=B9=D8=B9=E6=B6=A8=A3=AC=B2=BB=B5=C3=D4=
    =DA=B5=D8=B7=BD=C8=CE=BA=CE=CD=F8=D5=BE=C9=CF=B9=D2=CF=E0=D3=A6=B5=C4=B6=AB=
    =CE=F7=A3=AC=C7=EB=C4=E3=D4=DA=C4=E3=B5=C4=B2=A9=BF=CD=D6=D0</DIV>
    <DIV>&amp;nbsp;
    ......
    复制代码

    可以看到这封信的MIME语句是:

    MIME-Version: 1.0
    Content-Type: multipart/alternative; 
    boundary="----=_Part_287491_22998031.1213783671982"

    "Content-Type: multipart/alternative;"表明这封信的内容,是纯文本和HTML文本的混合。另两个可能的值是multipart/mixed和multipart/related,分别表示"信件内容中有二进制内容"和"信件带有附件"。

    "boundary="----=_Part_287491_22998031.1213783671982"
    "表明不同信件内容的分割线是"----=_Part_287491_22998031.1213783671982",它通常是一个很长的随机字符串。

    信件内容部分又有两个子信件头:

    Content-Type: text/plain; charset=gbk
    Content-Transfer-Encoding: base64

    Content-Type: text/html; charset=gbk
    Content-Transfer-Encoding: quoted-printable

    它们表明,第一个部分是gbk编码的纯文本,编码转换格式是base64。第二个部分是gbk编码的HTML文本,编码转化格式是quoted-printable。

    Base64 Encoding

    上面提到,MIME主要使用两种编码转换方式——Quoted-printable和Base64,将8位的非英语字符转化为7位的ASCII字符。这样做的初衷,是为了解决电子邮件中不能直接使用非ASCII码字符的规定,除此之外,还有其他重要意义:

    1、所有的二进制文件,都可以因此转化为可打印的文本编码,使用文本编辑器进行编辑;

    2、能够对文本进行简单的加密。

    Quoted-printable Encoding

    首先,简单介绍一下Quoted-printable编码转换方式。它主要用于ACSII文本中夹杂少量非ASCII码字符的情况,不适合于转换纯二进制文件。

    它规定将每一个8位的字节,转换为3个字符。

    第一个字符是"="号,这是固定不变的。

    后面二个字符是2个十六进制数,分别代表了这个字节前4位和后4位的数值。

    举例来说,ASCII码中"换页键"(form feed)是12,二进制形式是00001100,写成十六进制就是0C,因此它的编码值为"=0C"。"="号的ASCII值是61,二进制形式是00111101,因为它的编码值是"=3D"。除了可打印的ASCII码以外,所有其他字符都必须用这种方式进行转换。

    所有可打印的ASCII码字符(十进制值从33到126)都保持原样不变,"="(十进制值61)除外。

      

    Base64 Encoding

    所谓Base64,就是说选出64个字符----小写字母a-z、大写字母A-Z、数字0-9、符号"+"、"/"(再加上作为垫字的"=",实际上是65个字符)----作为一个基本字符集。然后,其他所有符号都转换成这个字符集中的字符。

    具体来说,转换方式可以分为四步。

    第一步,将每三个字节作为一组,一共是24个二进制位。

    第二步,将这24个二进制位分为四组,每个组有6个二进制位。

    第三步,在每组前面加两个00,扩展成32个二进制位,即四个字节。

    第四步,根据下表,得到扩展后的每个字节的对应符号,这就是Base64的编码值。

    复制代码
       0 A  17 R   34 i   51 z
      1 B  18 S   35 j   52 0
      2 C  19 T   36 k   53 1
      3 D  20 U   37 l   54 2
      4 E  21 V   38 m   55 3
      5 F  22 W   39 n   56 4
      6 G  23 X   40 o   57 5
      7 H  24 Y   41 p   58 6
      8 I  25 Z   42 q   59 7
      9 J  26 a   43 r   60 8
      10 K  27 b   44 s   61 9
      11 L  28 c   45 t   62 +
      12 M  29 d   46 u   63 /
      13 N  30 e   47 v
      14 O  31 f   48 w   
      15 P  32 g   49 x
      16 Q  33 h   50 y
    复制代码

    注意:Base64将三个字节转化成四个字节,因此Base64编码后的文本,会比原文本大出三分之一左右。

     举一个具体的实例,说明英语单词"Man"如何转成Base64编码。

    Text content M a n
    ASCII 77 97 110
    Bit pattern 0 1 0 0 1 1 0 1 0 1 1 0 0 0 0 1 0 1 1 0 1 1 1 0
    Index 19 22 5 46
    Base64-Encoded T W F u

    第1步,"M"、"a"、"n"的ASCII值分别是77、97、110,对应的二进制值是01001101、01100001、01101110,将它们连成一个24位的二进制字符串010011010110000101101110。

    第2步,将这个24位的二进制字符串分成4组,每组6个二进制位:010011、010110、000101、101110。

    第3步,在每组前面加两个00,扩展成32个二进制位,即四个字节:00010011、00010110、00000101、00101110。它们的十进制值分别是19、22、5、46。

    第4步,根据上表,得到每个值对应Base64编码,即T、W、F、u。

    因此,Man的Base64编码就是TWFu。

    如果要编码的字节数不能被3整除,最后会多出1个或2个字节,那么可以使用下面的方法进行处理:先使用0字节值在末尾补足,使其能够被3整除,然后再进行base64的编码。在编码后的base64文本后加上一个或两个'='号,代表补足的字节数。也就是说,当最后剩余一个八位字节(一个byte)时,最后一个6位的base64字节块有四位是0值,最后附加上两个等号;如果最后剩余两个八位字节(2个byte)时,最后一个6位的base字节块有两位是0值,最后附加一个等号。

    文本(1 Byte) A    
    二进制位 0 1 0 0 0 0 0 1                                
    二进制位(补0) 0 1 0 0 0 0 0 1 0 0 0 0                        
    Base64编码 Q Q    
    文本(2 Byte) B C  
    二进制位 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1     x x x x x x
    二进制位(补0) 0 1 0 0 0 0 1 0 0 1 0 0 0 0 1 1 0 0 x x x x x x
    Base64编码 Q k M

    即"A"的base64编码为"QQ==";"BC"的base64编码为"QkM="

    最后举一个中文的例子,汉字"严"如何转化成Base64编码?

    这里需要注意,汉字本身可以有多种编码,比如gb2312、utf-8、gbk等等,每一种编码的Base64对应值都不一样。下面的例子以utf-8为例。

    首先,"严"的utf-8编码为E4B8A5,写成二进制就是三字节的"11100100 10111000 10100101"。将这个24位的二进制字符串,按照第3节中的规则,转换成四组一共32位的二进制值"00111001 00001011 00100010 00100101",相应的十进制数为57、11、34、37,它们对应的Base64值就为5、L、i、l。

    所以,汉字"严"(utf-8编码)的Base64值就是5Lil。

  • 相关阅读:
    乐观锁与悲观锁——解决并发问题
    CentOS7 loaded active exited
    ubuntu安装phpVirtualBox web服务
    linux drwxr-xr-x 是什么意思
    phpmyadmin配置文件权限错误,不应任何用户都能修改
    转: CentOS安装jdk8
    PostgreSQL windows service启动失败
    PostgreSQL 添加自定义变量
    数据库检查约束是否存在
    转:PostgreSQL Cheat Sheet
  • 原文地址:https://www.cnblogs.com/zhaolizhe/p/6923507.html
Copyright © 2020-2023  润新知