19

我已经阅读了对“如何计算多部分 HTTP 请求内容长度?”的问题的相互矛盾且有些模棱两可的答复。具体来说,我想知道:

  • 计算“Content-length”标头的精确内容范围是多少?
  • CRLF ("\r\n") 八位字节序列算作一个还是两个八位字节?

有人可以提供一个明确的例子来回答这些问题吗?

4

4 回答 4

9

您的计算Content-Length方式不取决于有效负载的状态代码或媒体类型;它是线上的字节数。因此,编写您的多部分响应,计算字节数(并CRLF计为两个),并将其用于Content-Length.

见:http ://httpwg.org/specs/rfc7230.html#message.body.length

于 2016-11-21T23:01:37.377 回答
8

下面的活生生的例子应该有望回答这些问题。

使用 Google 的 OAuth 2.0 Playground 执行多部分请求

Google 的 OAuth 2.0 Playground 网页是针对 Google Drive 云执行多部分 HTTP 请求的绝佳方式。您无需了解有关 Google Drive 的任何内容即可执行此操作 - 我会为您完成所有工作。我们只对 HTTP 请求和响应感兴趣。但是,如果需要,使用 Playground 可以让您尝试多部分并回答其他问题。

创建用于上传的测试文件

我创建了一个名为“test-multipart.txt”的本地文本文件,保存在我的文件系统的某个位置。该文件大小为 34 字节,如下所示:

We're testing multipart uploading!

打开 Google 的 OAuth 2.0 Playground

我们首先在浏览器中打开 Google 的 OAuth 2.0 Playground,使用 URL https://developers.google.com/oauthplayground/

Google OAuth 2.0 Playground 打开屏幕

填写步骤 1

选择 Drive API v2 和“ https://www.googleapis.com/auth/drive ”,然后按“授权 API”:

为步骤 1 填写的字段

填写步骤 2

点击“兑换代币授权码”:

为步骤 2 填写的字段

填写步骤 3

在这里,我们提供所有相关的多部分请求信息:

  • 将 HTTP 方法设置为“POST”
  • 无需添加任何标题,Google 的 Playground 会添加所需的所有内容(例如标题、边界序列、内容长度)
  • 请求 URI:“ https://www.googleapis.com/upload/drive/v2/files?uploadType=multipart
  • 输入请求正文:这是 Google Drive 执行分段上传所需的一些元数据 JSON。我使用了以下内容:
{“title”:“test-multipart.txt”,“parents”:[{“id”:“0B09i2ZH5SsTHTjNtSS9QYUZqdTA”}],“properties”:[{“kind”:“drive#property”,“key”:“ cloudwrapper", "value": "true"}]}
  • 在“请求正文”屏幕的底部,选择 test-multipart.txt 文件进行上传。
  • 按“发送请求”按钮

在此处输入图像描述

请求和响应

Google 的 OAuth 2.0 Playground 奇迹般地插入了所有必需的标头,计算内容长度,生成边界序列,在需要的地方插入边界字符串,并向我们显示服务器的响应: 在此处输入图像描述

分析

多部分 HTTP 请求成功并带有 200 状态码,因此请求和响应是我们可以依赖的良好请求和响应。Google 的 Playground 插入了我们执行分段 HTTP 上传所需的一切。您可以看到“Content-length”设置为 352。让我们看看标题后面的空行之后的每一行:

--===============0688100289==\r\n
内容类型:应用程序/json\r\n
\r\n
{“title”:“test-multipart.txt”,“parents”:[{“id”:“0B09i2ZH5SsTHTjNtSS9QYUZqdTA”}],“properties”:[{“kind”:“drive#property”,“key”:“ cloudwrapper", "value": "true"}]}\r\n
--===============0688100289==\r\n
内容类型:文本/纯文本\r\n
\r\n
我们正在测试分段上传!\r\n
--===============0688100289==--

有九 (9) 行,我在前八 (8) 行的每一行末尾手动添加了“\r\n”(出于可读性原因)。以下是每行中的八位字节(字符)数:

  1. 29 + '\r\n'
  2. 30 + '\r\n'
  3. '\r\n'
  4. 167 + '\r\n'
  5. 29 + '\r\n'
  6. 24 + '\r\n'
  7. '\r\n'
  8. 34 + '\r\n' (虽然 '\r\n' 不是文本文件的一部分,但 Google 会插入它)
  9. 31

八位字节的总和为 344,将每个 '\r\n' 视为单个八位字节序列,我们得到了令人垂涎的内容长度 344 + 8 = 352。

概括

总结调查结果:

  1. 多部分请求的“内容长度”是从标题部分的空白行之后的边界序列的第一个字节计算出来的,并一直持续到最终边界序列的最后一个连字符,并且包括最后一个连字符。
  2. '\r\n' 序列应计为一 (1) 个八位字节,而不是两个,无论您运行的是什么操作系统。
于 2015-07-14T12:02:06.833 回答
3

如果 HTTP 消息具有Content-Length标头,则此标头指示 HTTP 标头之后的确切字节数。如果任何东西决定自由地算作\r\n一个字节,那么一切都会崩溃:保持活动的 http 连接将停止工作,因为 HTTP 堆栈将无法看到下一条 HTTP 消息从哪里开始,并且会尝试解析随机数据,就好像它一样是一条 HTTP 消息。

于 2017-05-18T08:52:24.107 回答
1

\n\r 是两个字节。

Moshe Rubin 的回答是错误的。该实现在那里被窃听。

我发送了一个 curl 请求来上传文件,并使用 WireShark 专门收集我的网络发送的确切实际数据。每个人都应该同意的方法比某个地方的在线申请更有效。

--------------------------de798c65c334bc76\r\n
Content-Disposition: form-data; name="file"; filename="requireoptions.txt"\r\n
Content-Type: text/plain\r\n
\r\n
Pillow
pyusb
wxPython
ezdxf
opencv-python-headless
\r\n--------------------------de798c65c334bc76--\r\n

Curl,每个人都会同意可能正确地实现了这一点: Content-Length: 250

> len("2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d646537393863363563333334626337360d0a436f6e74656e742d446973706f736974696f6e3a20666f726d2d646174613b206e616d653d2266696c65223b2066696c656e616d653d22726571756972656f7074696f6e732e747874220d0a436f6e74656e742d547970653a20746578742f706c61696e0d0a0d0a50696c6c6f770d0a70797573620d0a7778507974686f6e0d0a657a6478660d0a6f70656e63762d707974686f6e2d686561646c6573730d0a2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d2d646537393863363563333334626337362d2d0d0a")
500

(2x250 = 500,从 WireShark 复制十六进制流。)

我在那里拿了实际的二进制文件。'2d' 是 --- 开始边界。

请注意,将错误的计数分配给将 0d0a 视为 1 而不是 2 个八位字节的服务器(这太疯狂了,它们是八位字节并且不能是复合的),主动拒绝了错误的请求。


此外,这回答了问题的第二部分。实际的内容长度就是这里的一切。从第一个边界到结尾处的最后一个边界,--\r\n所有的八位字节都留在了线路中。

于 2021-01-22T13:06:48.587 回答