HTTP POST中的各个字段是否有大小限制?

时间:2018-03-30 19:13:36

标签: apache http post http-post jetty

我有一个用于文件上传的API,需要提交多部分表单。但是我有一个客户在编写客户端,他的系统无法正确生成multipart/form-data请求。他要求我修改我的API以接受application/x-www-form-urlencoded请求中的文件,文件名在一个键/值对中,文件内容base64编码在另一个键/值对中。

原则上我可以很容易地做到这一点(之后我需要淋浴),但我担心尺寸限制。我们在Production中预期的文件相当大:5-10MB,有时高达20MB。我找不到任何告诉我表格POST中个别键/值对数据长度限制的内容,无论是在规格中(我已经看过,HTTP specForms spec )或在特定实现中(我的API在Java应用程序服务器Jetty上运行,前面有一个Apache HTTP服务器)。

POST表单中键/值对中单个值的技术和实际限制是什么?

1 个答案:

答案 0 :(得分:0)

HttpConfiguration类上存在人为限制,配置。最大数量的密钥和请求正文内容的最大大小。

实际上,这是一个非常糟糕的主意。

您将拥有一个String,每个字符使用2个字节作为Base64数据。 而你只有33%的开销只是Base64。

他们还必须对各种特殊字符(例如" +"它们在Base64中有意义,但是空格"" in)中的utf8 urlencode urlencoded form。因此他们需要将" +"编码为"%2B")。

因此,对于一个20MB的文件,您将拥有......

20,971,520字节的原始数据,在原始Base64中表示为27,892,122个字符,在urlencoded时使用(平均)29,286,728个字符,它将以字符串形式使用58,573,455字节的内存。

Jetty上的解码过程将获取传入的原始urlencoded字节,并在解码urlencoded格式之前在String中分配2x大小。所以这是一个长度为58,573,456的java.lang.String(它为字符串使用了117,146,912字节的堆内存,并且不要忘记保存29MB的字节缓冲数据!)只是为了将Base64二进制文件解码为x-www-form-urlencoded字符串形式的值。

我会反击并强制他们正确使用multipart/form-data。有很多好的库可以正确地生成表单数据。

如果他们使用Java,请告诉他们使用Apache HttpComponents项目中的httpmime库(他们不必使用/使用/安装Apache Http Client来使用httpmime,它是一个独立的库)。

替代方法

没有必要说你必须使用application/x-www-form-urlecnodedmultipart/form-data

通过application/octet-stream

提供原始上传选项

他们使用POST,并且必须包含以下有效请求标头...

Connection: close
Content-Type: application/octet-stream
Content-Length: <whatever_size_the_content_is>
  • Connection: close表示http协议何时完成。
  • Content-Type: application/octet-stream表示Jetty不会将该内容作为请求参数处理,也不会对其应用字符集翻译。
  • Content-Length是确保发送/接收整个文件所必需的。

然后将原始二进制字节流式传输给您。

这仅适用于文件内容,如果您有其他需要传入的信息(例如文件名),请考虑使用查询参数或自定义请求标头(例如:X-Filename: secretsauce.doc

在您的servlet上,您只需使用HttpServletRequest.getInputStream()来获取这些字节,并使用Content-Length变量来验证您是否收到了整个文件。

或者,您可以让它们在请求标头中提供SHA1哈希值,例如X-Sha1Sum: bed0213d7b167aa9c1734a236f798659395e4e19,然后您可以使用它来验证整个文件是否已正确发送/接收。