【问题标题】:Indy 10 + XE8 multipart upload with long filenameIndy 10 + XE8 长文件名分段上传
【发布时间】:2017-02-20 17:15:09
【问题描述】:

我正在尝试使用 TIdMultipartFormDataStream 执行 multipart upload to Box.com。虽然文件名最多为 '\u0424\u042B\u0412\u0410\u041F.txt' 它可以正常工作,但是当它更长时('\u0424\u042B\u0412\u0410\u041F\u0420.txt')它会导致'HTTP /1.1 400 错误请求'。

FormField.FFieldValue 长度有限制吗?如果是这样,有没有办法绕过它?

procedure TBoxComSaveFilter.UploadTest;
const
  URL = 'https://upload.box.com/api/2.0/files/content';
var
  IdHTTP: TIdHTTP;
  MD: TIdMultipartFormDataStream;
begin
  IdHTTP := TIdHTTP.Create(nil);
  try
    IdHTTP.HandleRedirects := True;
    IdHTTP.IOHandler := TIdSSLIOHandlerSocketOpenSSL.Create(IdHTTP);
    IdHTTP.Request.BasicAuthentication := False;
    IdHTTP.Request.CustomHeaders.Values['Authorization'] := 'Bearer ' + FAccessToken;
    MD := TIdMultipartFormDataStream.Create;
    try
      MD.AddFormField('metadata', '{"name": "' +
        '\u0424\u042B\u0412\u0410\u041F.txt' +       // => OK
//        '\u0424\u042B\u0412\u0410\u041F\u0420.txt' + // => 400 Bad Request
        '", "parent": {"id": "0"}}', '', 'application/json');

      MD.AddFile('content', 'source.txt', 'application/octet-stream');
      IdHTTP.Post(URL, MD);
    finally
      MD.Free;
    end;
  finally
    IdHTTP.Free;
  end;
end;

短文件名的部分日志:

Sent 20.02.2017 21:16:26: ----------022017211625520
Content-Disposition: form-data; name="metadata"
Content-Type: application/json
Content-Transfer-Encoding: quoted-printable

{"name": "\u0424\u042B\u0412\u0410\u041F.txt", "parent": {"id": "0"}}
----------022017211625520

长文件名的相同部分:

Sent 20.02.2017 21:17:48: ----------022017211748412
Content-Disposition: form-data; name="metadata"
Content-Type: application/json
Content-Transfer-Encoding: quoted-printable

{"name": "\u0424\u042B\u0412\u0410\u041F\u0420.txt", "parent": {"id": =
"0"}}
----------022017211748412

我可以看到数据在 70 字节后被“=CRLF”分割。

【问题讨论】:

  • TIdMultipartFormDataStream 本身没有限制,但在 Box 的末尾有:“Box 仅支持 255 个字符或更少字符的文件名。不支持的名称是包含不可打印的 ascii、/ 或 \、带有尾随空格的名称和特殊名称“.”和“..”。
  • 为什么你要对 Unicode 字符进行 JSON 编码呢?你不应该这样做:MD.AddFormField('metadata', '{"name": "ФЫВАПР.txt", "parent": {"id": "0"}}', 'utf-8', 'application/json');
  • 谢谢@RemyLebeau。我尝试了“ФЫВАПР.txt”和“utf-8”,结果是“HTTP/1.1 400 Bad Request”。日志:{"name": "=D0=A4=D0=AB=D0=92=D0=90=D0=9F=D0=A0.txt", "parent": {"id": =CRLF"0"}}
  • 很抱歉我一开始跳过了日志。在我看来,根据日志,Indy 将数据拆分为“=CRLF”。

标签: delphi indy delphi-2009 box indy10


【解决方案1】:

文本字段的默认传输编码是 MIME 的quoted-printable 格式。 Box 似乎不喜欢这种格式。

AddFormField() 返回一个TIdFormDataField,它有一个ContentTransfer 属性,您可以将其设置为8bitbinary 以按原样发送JSON 文本(在字符集编码为字节后,即):

MD.AddFormField('metadata', '{"name": "ФЫВАПР.txt", "parent": {"id": "0"}}', 'utf-8', 'application/json').ContentTransfer := '8bit';

或者,将您的 JSON 放入 TStream,例如 TStringStreamTMemoryStream,然后使用 AddFormField()TStream 重载,默认情况下将 ContentTransfer 设置为 binary

JsonStream := TStringStream.Create('{"name": "ФЫВАПР.txt", "parent": {"id": "0"}}', TEncoding.UTF8);
try
  MD.AddFormField('metadata', 'application/json', 'utf-8', JsonStream);
  // send the post...
finally
  JsonStream.Free;
end;

【讨论】:

猜你喜欢
  • 2017-06-28
  • 1970-01-01
  • 1970-01-01
  • 2015-03-14
  • 1970-01-01
  • 1970-01-01
  • 2021-02-25
  • 2016-11-09
  • 1970-01-01
相关资源
最近更新 更多