使用 Indy 发布并且文件名包含希腊字符时文件上传失败

2023-11-30

我正在尝试实施一个POST到网络服务。我需要发送一个类型为可变的文件(.docx, .pdf, .txt) 以及 JSON 格式的字符串。

我已成功使用类似于以下的代码成功发布文件:

procedure DoRequest;
var
  Http: TIdHTTP;
  Params: TIdMultipartFormDataStream;
  RequestStream, ResponseStream: TStringStream;
  JRequest, JResponse: TJSONObject;
  url: string;
begin
  url := 'some_custom_service'

  JRequest := TJSONObject.Create;
  JResponse := TJSONObject.Create;
  try
    JRequest.AddPair('Pair1', 'Value1');
    JRequest.AddPair('Pair2', 'Value2');
    JRequest.AddPair('Pair3', 'Value3');

    Http := TIdHTTP.Create(nil);           
    ResponseStream := TStringStream.Create;
    RequestStream := TStringStream.Create(UTF8Encode(JRequest.ToString));
    try   
      Params := TIdMultipartFormDataStream.Create;
      Params.AddFile('File', ceFileName.Text, '').ContentTransfer := '';
      Params.AddFormField('Json', 'application/json', '', RequestStream);

      Http.Post(url, Params, ResponseStream);
      JResponse := TJSONObject.ParseJSONValue(ResponseStream.DataString) as TJSONObject;
    finally    
      RequestStream.Free;
      ResponseStream.Free;
      Params.Free;
      Http.Free;
    end;
  finally
    JRequest.Free;
    JResponse.Free;
  end;
end;

当我尝试发送文件名中包含希腊字符和空格的文件时,会出现此问题。有时会失败,有时会成功。

经过大量研究后,我注意到POST标头由 Indy 编码TIdFormDataField类使用EncodeHeader()功能。当发布失败时,标头中的编码文件名会被分割,而成功发布时则不会分割。

例如 :

  • Επιστολή εκπαιδευτικο.docx被编码为=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66zr8uZG9j?='#$D#$A' =?UTF-8?B?eA==?=,失败了。
  • Επιστολή εκπαιδευτικ.docx被编码为=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66LmRvY3g=?=,成功了。
  • Επιστολή εκπαιδευτικ .docx被编码为=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66?= .docx,失败了。

我尝试更改文件名的编码AContentType of the AddFile()程序,以及ContentTransfer,但这些都不会改变行为,并且当编码的文件名被分割时我仍然会收到错误。

这是某种错误,还是我错过了什么?

我的代码适用于除上面描述的情况之外的所有情况。

我正在使用 Delphi XE3 和 Indy10。


EncodeHeader()Unicode 字符串确实存在一些已知问题:

在相邻编码字之间分割数据时,EncodeHeader() 需要考虑代码单元

基本上,MIME 编码的单词长度不能超过 75 个字符,因此长文本会被分割。但是,当对长 Unicode 字符串进行编码时,任何给定的 Unicode 字符都可以使用 1 个或多个字节进行字符集编码,并且EncodeHeader()尚未避免错误地将两个单独字节之间的多字节字符拆分为单独的编码字(这是非法的,并且被明确禁止)RFC 2047MIME 规范)。

但是,这并不是您的示例中发生的情况。

在你的第一个例子中,'Επιστολή εκπαιδευτικο.docx'太长而无法编码为单个 MIME 单词,因此它被分成'Επιστολή εκπαιδευτικο.doc' 'x'子字符串,然后单独编码。对于长文本,这在 MIME 中是合法的(尽管您可能期望 Indy 将文本拆分为'Επιστολή' ' εκπαιδευτικο.doc'相反,或者甚至'Επιστολή' ' εκπαιδευτικο' '.doc'。这可能是未来版本中的可能性)。仅由空格分隔的相邻 MIME 单词在解码时将连接在一起而不分隔空格,从而产生'Επιστολή εκπαιδευτικο.docx'再次。如果服务器没有这样做,则它的解码器有缺陷(也许它正在解码为'Επιστολή εκπαιδευτικο.doc x'反而?)。

在你的第二个例子中,'Επιστολή εκπαιδευτικ.docx'足够短,可以编码为单个 MIME 单词。

在你的第三个例子中,'Επιστολή εκπαιδευτικ .docx'在第二个空白(不是第一个)上被分割成'Επιστολή εκπαιδευτικ' ' .docx'子串,并且只需要对第一个子串进行编码。这在 MIME 中是合法的。解码时,解码后的文本将与以下未编码文本连接,保留它们之间的空格,从而产生'Επιστολή εκπαιδευτικ .docx'再次。如果服务器没有这样做,则它的解码器有缺陷(也许它正在解码为'Επιστολή εκπαιδευτικ.docx'反而?)。

如果您通过 Indy 的 MIME 标头编码器/解码器运行这些示例文件名,它们会正确解码:

var
  s: String;
begin
  s := EncodeHeader('Επιστολή εκπαιδευτικο.docx', '', 'B', 'UTF-8');
  ShowMessage(s); // '=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66zr8uZG9j?='#13#10' =?UTF-8?B?eA==?='
  s := DecodeHeader(s);
  ShowMessage(s); // 'Επιστολή εκπαιδευτικο.docx'

  s := EncodeHeader('Επιστολή εκπαιδευτικ.docx', '', 'B', 'UTF-8');
  ShowMessage(s); // '=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66LmRvY3g=?='
  s := DecodeHeader(s);
  ShowMessage(s); // 'Επιστολή εκπαιδευτικ.docx' 

  s := EncodeHeader('Επιστολή εκπαιδευτικ .docx', '', 'B', 'UTF-8');
  ShowMessage(s); // '=?UTF-8?B?zpXPgM65z4PPhM6/zrvOriDOtc66z4DOsc65zrTOtc+Fz4TOuc66?= .docx' 
  s := DecodeHeader(s);
  ShowMessage(s); // 'Επιστολή εκπαιδευτικ .docx'
end;

所以问题似乎出在服务器端解码上,而不是 Indy 的客户端编码上。

话虽这么说,如果您使用的是 Indy 10 的最新版本(2011 年 11 月或更高版本),TIdFormDataField has a HeaderEncoding属性,默认为'B'(base64) 在 Unicode 环境中。然而,分裂逻辑也会影响'Q'(quoted-printable) 也一样,所以这可能对你有用,也可能不适合你(但你可以尝试一下):

with Params.AddFile('File', ceFileName.Text, '') do
begin
  ContentTransfer := '';
  HeaderEncoding := 'Q'; // <--- here
  HeaderCharSet := 'utf-8';
end;

否则,解决方法可能是将值更改为'8'(8 位),这有效地禁用 MIME 编码(但不是字符集编码):

with Params.AddFile('File', ceFileName.Text, '') do
begin
  ContentTransfer := '';
  HeaderEncoding := '8'; // <--- here
  HeaderCharSet := 'utf-8';
end;

请注意,如果服务器不希望文件名使用原始 UTF-8 字节,您可能仍然会遇到问题(即,'Επιστολή εκπαιδευτικο.docx'被解释为'Επιστολή εκπαιδευτικο.docx', 例如)。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

使用 Indy 发布并且文件名包含希腊字符时文件上传失败 的相关文章

  • VCL.位图到 FMX.位图

    我在网上找到了这段代码 但 FMX Bitmap 没有扫描线 是否可以以某种方式将 VCL TBitmap 复制或绘制到 FMX Bitmap IFDEF MSWINDOWS type TBitmap FMX Types TBitmap T
  • C++ 字符串:UTF-8 还是 16 位编码?

    我仍在尝试决定我的 家庭 项目是否应该使用UTF 8 http en wikipedia org wiki UTF 8字符串 根据 std string 实现 必要时带有附加的 UTF 8 特定函数 或一些 16 位字符串 作为 std w
  • 如何在 Vista 上安装 Delphi 7

    我多次尝试在 Vista 上安装 Delphi 7 但 Vista 告诉我此应用程序 Delphi 7 存在已知问题 从而阻止了我这样做 我公司的其他几个人在 Vista 上安装 D7 时遇到了问题 由此得出的结论是 我们的 D7 应用程序
  • 如何在 OSX 上的应用程序名称下创建子项菜单?

    如何在下面添加TMenuItemProject1以上Quit在下面的屏幕截图上 我创建了一个 TMenuBar 并选中了 UseOSMenu 属性 我添加的第一个 TMenuItem 是主栏中的第二个 TMenuItem 您可以通过将 II
  • 加载 Jpg/Gif/Bitmap 并转换为 Bitmap

    我必须从 XML 文件加载图像 XML 文件中没有关于图像是否为 JPG GIF BMP 的信息 加载图像后 我需要将其转换为位图 有谁知道如何在不知道实际文件格式的情况下将图像转换为位图 我正在使用 Delphi 2007 2009 谢谢
  • Delphi - 自XE8以来如何正确注册图形类?

    我正在编写一个 Delphi 包 它提供了一个新的自定义 TGraphic 对象 允许读取 VCL 组件 如 TImage 中的新图像格式 我最初使用 RAD Studio XE7 开发了这个包 并且运行良好 然而 我最近迁移到了较新的 R
  • 将 Scala Dataframe 写入 CSV 文件时应用 UTF8 编码

    在 Spark2 Scala 中将数据帧写入 CSV 文件时如何正确应用 UTF8 编码 我正在使用这个 df repartition 1 write mode SaveMode Overwrite format csv option he
  • 带位图的简单组合框

    如何将位图放入组合框中并将样式设置为简单 例如 Google Chrome 的右侧有星号 Firefox 的右侧有箭头 我尝试了这段代码 procedure TForm2 ComboBox1DrawItem Control TWinCont
  • 替换非 UTF8 字符

    在 php 中 我需要替换字符串中的所有非 UTF8 字符 然而 并不是通过某种等价物 比如iconv功能与 TRANSLIT 但是由一些选定的角色 例如 or 例如 通常 我希望用户能够看到找到无效字符的位置 我没有找到任何执行此操作的函
  • 我如何在Delphi中处理事件?

    例如 我有一个程序 在单击 Button1 后执行某些操作 如果没有 Button1Click 中的代码 如何处理按钮的 onclick 事件 我需要为 Button1 动态添加事件 unit Unit1 interface uses Wi
  • 有人用CrossKylix进行真正的跨平台开发吗?

    新版本克罗斯凯利克斯 http crosskylix untergrund net 两周前更新过 即使 Kylix 已经停产很久了 但它似乎仍然被一些 Delphi 开发人员使用 有人在 Windows 和 Linux 的跨平台开发中成功使
  • 如何在调试器中显示 TStringList 的内容?

    我想在调试应用程序时显示 TStringList 的全部内容 相反 我只是得到指示 Flist 仅显示地址 如果您使用的是 Delphi 2010 或更高版本 调试器允许使用调试可视化工具 http docwiki embarcadero
  • TCPDF UTF-8 符号未显示

    我使用最新的 TCPDF 版本 5 9 但在编码方面遇到一些奇怪的问题 我需要立陶宛语语言符号 例如 但只能得到其中的一小部分 其他的还是这样 所以我该怎么做 我使用默认的 times 字体 它带有 TCPDF 下载 任何帮助 将不胜感激
  • 不断断点?如何去除它们?

    我下载了一个用Delphi 2009制作的项目 这也是我使用的 但是有一个断点我无法删除 如果我尝试删除它 它会在程序执行后再次执行 我在其他调试器中遇到了这样的事情 称为硬件断点 但这并不重要 如何删除断点 EDIT Article ht
  • 具有 csOwnerDrawFixed 样式的组合框如何表现得像 csDropDown 样式?

    我正在使用一个组合框 http docwiki embarcadero com Libraries en Vcl StdCtrls TComboBoxstyle 属性设置为的组件csOwnerDrawFixed 我实现了绘图项一切工作正常
  • 当responseText包含有效的Xml时,IXMLHttpRequest.responseXml为空,没有解析错误

    我正在从中获取一些 XML政府网站 http www bankofcanada ca stats assets rates rss noon en all xml http www bankofcanada ca stats assets
  • delphi中如何实现多重继承?

    我正在对一个旧库进行完全重写 我不确定如何处理这种情况 为了便于理解 大家都欢呼自行车类比 我有以下课程 TBike 自行车本身 TBikeWheel 自行车的一个轮子 TBikeWheelFront and TBikeWheelBack
  • 用于 UTF8 到 1252 的 Windows C API

    我熟悉 WideCharToMultiByte 和 MultiByteToWideChar 转换 可以使用它们来做类似的事情 UTF8 gt UTF16 gt 1252 我知道 iconv 会满足我的需要 但是有人知道任何 MS 库可以在一
  • 将数据从一个数据集结构移动到另一个数据集结构的更快方法(在 TDatasetProvider 中)

    我有一个自定义的 TDatasetProvider 它允许为其提供的任何数据创建新字段 因此 假设您在原始数据集上获得了以下字段 客户ID Name Age 您需要使用显示位图在 DBGrid 上选择它 好吧 你可以 因为我的 DSP 可以
  • Delphi AES 库 (Rijndael) 使用 KAT Vectors 进行测试

    对于这两个库 Delphi 加密概要 v 5 2 http code google com p delphidec TurboPower 密码箱 v 2 07 http lockbox seanbdurkin id au tiki list

随机推荐

  • Ubuntu Python“没有名为 paramiko 的模块”

    所以我尝试在 Ubuntu 上使用 Python 2 7 使用 Paramiko 但是 import paramiko 会导致此错误 Traceback most recent call last File
  • 在excel vba中使用数组或字典作为sql中的from子句

    是否可以使用数组或字典作为 SQL 语句中的表 例如 strSQL SELECT FROM myArray 提前致谢 扩展 Nathan Sav 提供的想法 以下代码应该 Dim a 3 As String a 0 1 as C1 a 1
  • 在 Git 中仅提交文件的部分更改

    当我在 Git 中更改文件时 如何才能仅提交部分更改 例如 如何仅提交文件中已更改的 30 行中的 15 行 您可以使用 git add patch
  • Scala:用最后一个非空值填充列表中的空白

    我有一个类似的列表 val arr Array a b c 我正在寻找一种方法来创建 Array a a a b c c 您可以尝试使用折叠 简单 易于理解 的方法是向左折叠 Array empty String arr case prev
  • 如何打开 Excel 工作簿而不显示消息 该工作簿包含指向其他数据源的链接。以编程方式?

    我想以编程方式打开 1 个或多个 Excel 工作簿 当我打开工作簿时 你会得到一个问题 该工作簿包含其他数据源的链接 我不想按 不更新 您如何离开此消息框 所以功能不会再中断 不需要更新 尝试放入工作簿打开事件处理程序 Applicati
  • InternalsVisibleTo 的替代方案

    我目前正在尝试在我的解决方案中编写单元测试 但我想将单元测试放在不同的单独项目中 问题是当我生成一些假测试数据时 我需要设置类的属性 但这是不可能的 因为属性具有私有 内部设置 我找到了一种使用属性仅向某些项目公开内部属性的方法Intern
  • 如何获取生成的 java 进程的 PID

    我正在编写几个 java 程序 在完成我想做的任何事情后 需要在单独的 JVM 中杀死 清理 为此 我需要获取我正在创建的 java 进程的 PID jps l可在 Windows 和 Unix 上运行 您可以使用 java 程序调用此命令
  • 带 url 重定向的 Rails 句柄 404

    我希望使用 Rails 将链接重定向到互联网上 我确信这些链接从我的旧域到新域 我想使用地址 example com about about 将不再存在 在我的 application controller 中获取 404 检查 url 然
  • NSDate 因连续操作而崩溃

    我下面有以下代码 旨在将名为 today 的类变量向前或向后更改一天 它会工作一次 但之后就会崩溃 无论我按左键还是右键 它都会做同样的事情 我究竟做错了什么 今天的 var 是一个类 var 发起为 today NSDate date 这
  • VBA Powerpoint - 如何突出显示选定的文本

    我想将所选文本突出显示为某种颜色 但这不起作用 你能帮我吗 Sub ShadingLtYellow ActiveWindow Selection TextRange HighlightColor RGB RGB 255 255 175 En
  • 为什么 Pinia/Vuex 比具有服务类的经典方法更受青睐? [关闭]

    Closed 这个问题是基于意见的 目前不接受答案 皮尼亚 Vuex Pinia Vuex 以及 Redux 被设计为 单一事实来源 您可以拥有一个或多个存储来保存应用程序数据 并且可以从任何地方获取这些数据 Pinia 商店如下所示 ex
  • 如何在nuxt中添加流(flowtype)支持?

    我想为 nuxt 项目添加流支持 我的项目使用 webpack 和 babel 我可以在某处找到工作示例吗 如果我跑flow check 没有错误 当我运行时yarn run dev 我收到语法错误 我知道有这些未答复的 问题在那里 我再次
  • 编码返回“未知”

    对于这个例子 http pastebin com QyebfD1pz3 和 cvc4 返回 未知 作为 check sat 的结果 两者对于原因都不是很详细 有没有办法让 z3 关于其执行更加详细 你的脚本使用了这个策略 s Then si
  • IE6 中的 event.currentTarget

    我有一个事件处理程序 我将其附加到一个元素以捕获冒泡的单击事件 我需要一个reliable获取元素的方法caught事件 而不是触发它的元素 该特定元素高于 srcElement target 的级别数量是任意的 因此使用 ParentNo
  • 使用 WebServiceTemplate 设置自定义标头

    我在 Spring Boot 中使用 WebServiceTemplate 并使用 marshalSendAndReceive 调用目标服务 如何在请求中设置自定义 HTTP 标头 您需要使用 WebServiceMessageCallba
  • 在 dropwizard 中运行异步作业并轮询其状态

    在 dropwizard 中 我需要实现异步作业并轮询它们的状态 我在资源中有两个端点 Path jobs Component public class MyController POST Produces MediaType APPLIC
  • 在 mac 中安装 PHP INTL 不正确

    我已经安装了php56 intl using Homebrew像这样 brew install php56 intl当我这样做时php m grep intl它给了我intl 但是当我检查我的phpinfo 文件 不显示intl 不知道我错
  • 导致 JavaFX 2.0 中 TableView 不响应鼠标单击

    我想要一个 JavaFX 2 0 TableView 但我不希望它响应鼠标单击 当然 我可以禁用控件 小部件 但它会显示为禁用 tableview setSelectionModel null 给出了我想要的行为 但 UI 转储了抱怨 nu
  • 在 Flex 中的组件之间共享数据的最佳方式是什么?

    我正在为新工作开发一个 Flex 应用程序 这有点像一个训练轮应用程序 我正在学习这门语言 这不是一个需要与服务对话才能完成工作的应用程序 整个应用程序中有一些组合框实例共享相同的一组可能值 例如 选择状态 进行中 拒绝 完成 我希望它们使
  • 使用 Indy 发布并且文件名包含希腊字符时文件上传失败

    我正在尝试实施一个POST到网络服务 我需要发送一个类型为可变的文件 docx pdf txt 以及 JSON 格式的字符串 我已成功使用类似于以下的代码成功发布文件 procedure DoRequest var Http TIdHTTP