Http/Smtp MIME多部分。为什么需要边界?

4

我有一个关于这些协议设计的问题。为什么我们要使用边界来分隔多部分消息的不同部分,而不是为每个部分引入内容长度?使用长度参数会使解析更容易。我是否忽略了使用边界而不是长度参数的一些主要原因?谢谢!


@VariabileAleatoria 我认为Steffen的回答是你在寻找的。这是一件从过去延续下来的事情,在许多不同的背景中都被使用。 - Brad
3个回答

3

使用长度参数会让解析更容易

这里你是错误的。多部分 MIME 的作者考虑到了一些情况,你无法预先确定消息部分的长度。想想那些改变消息长度的内容编码,如 base64、UUencode 等等。还有压缩、加密等等。另外:Content-Length 是一个实体头。这意味着如果你到达它,你已经开始解析消息部分了。与边界标记相比,它没有任何优势。

如果你研究旧协议,你会经常遇到某个标记(通常是 \0),表示消息的结束。发送消息字节数的另一种解决方案,但在需要实时转换消息内容或以某种方式流式传输消息内容的地方,你不会经常找到它。

底线:多部分边界允许在消息内容大小不可预测的情况下进行一些有趣的应用。HTTP 服务器推送 就是一个显著的例子。


1
但这取决于您如何定义内容长度。您始终可以将其视为当前部分实际发送的字节数(在编码和/或压缩之后)。在这种情况下,您只需计数而不是模式匹配即可知道何时完成该部分。我是否漏掉了什么? - Michael
1
是的。如果您动态生成消息内容或者资源受限,无法整体处理消息部分,则无法执行此操作。为了符合现今的标准,请想象多个千兆字节大小的消息。顺便说一下:Content-Length头部的定义与您在这里写的完全相同。 - DaSourcerer
1
是的,通过在每个数据块前加上长度,并以特殊方式标记最后一个数据块,您可以在不事先知道总大小的情况下传输数据。这比多部分 MIME 更容易解析。这是在 HTTP 分块传输编码中完成的。 - Steffen Ullrich
Steffen,谢谢!Http分块传输在解释问题时非常有帮助。 - Michael
1
如果发送者事先不知道内容,他如何确保边界不会出现在有效载荷中? - xmjx
显示剩余3条评论

2
因为在过去的好日子里,MIME标准是这样定义的。其中一个原因可能是content-length在text/plain数据中存在问题,其中换行可能是CR(旧版mac),LF(unix)或CR LF(windows,dos)。另一个可能是它更容易让人类阅读,这是我个人认为的一个不好的论点,但在偏爱HTTP、XML或SOAP等文本表示而不是ASN.1或SUN RPC这种更有效的二进制方式时,经常会发生这种情况。您也可以将其视为工业界通过将无用的开销引入协议来销售更强大的服务器的成功尝试 :)

非常感谢Stefan!只是一个后续问题。你提到了行尾符号可能出现的问题。但是为什么呢?Content-Length只会计算实际符号(cr或cr+lf)。为什么在解析时会引发问题呢? - Michael
是的,在HTTP Post请求中,我们使用内容长度来表示整个消息体的大小,并使用边界来分隔各个部分。因此,总结起来,从概念上讲,我们可以毫无问题地使用一种设计,其中不使用边界,而是使用以字节为单位测量的内容长度来表示多部分消息的每个部分。正确吗? - Michael
在HTTP POST请求中,我们使用内容长度来表示整个消息体的大小。这实际上是一种“最佳”做法,但不是必需的。如果你研究RFC 2616,你会发现所有参与方都需要理解分块编码。因此,你可以在没有消息大小的情况下以块编码方式发送POST请求。然而,服务器对此的支持较少,所以发送消息大小是首选的方法。 - DaSourcerer
嗯,我不太同意。当传输编码被剥离并且消息体被传递给Web应用程序时,服务器的责任就结束了。解析消息体已经是Web应用程序的职责了,在我看来。顺便说一句:如果多部分消息携带任何文件,那么它们只在HTML表单中才相关。其他所有内容都应该以application/x-www-form-urlencoded的方式发送,这是更紧凑的格式方式 ;) - DaSourcerer
我同意你的观点。然而,有更简单、更高效的方法来将消息正文中的各个部分分开(我并不是指XML,因为它甚至更糟糕)。 - Steffen Ullrich
显示剩余4条评论

1

除了DaSourcerer在他的回答中提到的内容之外,我想要指出有很多合理的原因为什么一个人可能不知道内容的长度。在评论中,最有说服力的理由已经被提及:流传输。

停止思考"文件大小"或者甚至"文件",朋友们!当构建一个MIME多部分时,创建者可能根本不读取文件而是输入流,或者她可能逐行从平台相关的读取器中读取,这又引入了LF与CRLF的问题。流可能如此庞大,以至于在将其写出之前完全读取它会非常低效甚至不可能,仅仅为了确定其大小。

最后但同样重要的是,RFC 1341规定多部分实体可以有序言(第一个边界之前的内容)和结语(最后一个边界之后的内容)。引用:

From: Nathaniel Borenstein <nsb@bellcore.com> 
To:  Ned Freed <ned@innosoft.com> 
Subject: Sample message 
MIME-Version: 1.0 
Content-type: multipart/mixed; boundary="simple 
boundary" 

This is the preamble.  It is to be ignored, though it 
is a handy place for mail composers to include an 
explanatory note to non-MIME compliant readers. 
--simple boundary 

This is implicitly typed plain ASCII text. 
It does NOT end with a linebreak. 
--simple boundary 
Content-type: text/plain; charset=us-ascii 

This is explicitly typed plain ASCII text. 
It DOES end with a linebreak. 

--simple boundary-- 
This is the epilogue.  It is also to be ignored.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接