【问题标题】:Handling BabyFTP MKD 250 response with Indy使用 Indy 处理 BabyFTP MKD 250 响应
【发布时间】:2017-09-13 15:12:40
【问题描述】:

我使用 BabyFTP 作为 Delphi 10.1 Berlin 应用程序的嵌入式 FTP 服务器。尽管我仍然不确定它是否是我可以满足我要求的最好的轻量级 FTP 服务器,但它似乎运行良好......除了一个细节:

在成功的 MKD 命令中,BabyFTP 以 250 响应,而不是预期的(由 RFC 和 Indy)257。因此,TIdFTP 引发了 EIdReplyRFCError 异常,它中断了我的信息流'正在尝试做(将 blob 字段保存到文件):

s := TBytesStream.Create;
Try
  Field.SaveToStream(s);
  MakeDir(TPath.GetDirectoryName(url));
  Put(s, url);
Finally
  s.Free;
End;

当然,我知道我可以将 MakeDir 行包装在 Try except 块中并忽略特定的异常类型。但这似乎有点冒险,因为从引发的异常我不能确定我得到了 250 或其他一些真正的错误。

我尝试查看 Indy 的响应代码是否可配置,但似乎它们在特定方法中是硬编码的。子类化 TIdFTP 是不可行的,因为方法不是虚拟的。我可以自定义 IdFTP.pas 单元,但我不想这样做,因为我在一个团队中工作,而且我不想将补丁分发到标准 Delphi 单元。

我可以使用另一台 FTP 服务器...但我想它们中的大多数都有一些像这个一样不完全标准的功能。

有人知道其他解决方法吗?雷米?

【问题讨论】:

  • 引发的异常不会暴露状态码吗?然后您可以处理(并忽略)该特定情况。编辑:参见EIdReplyRFCError.ErrorCode 属性。
  • @OndrejKelle:很好......我正在查看描述(已删除响应代码)并且没有考虑寻找此类异常的特定属性。除了对 ErrorCode 的测试之外的尝试有效。将其发布为答案,我会接受。

标签: delphi ftp indy


【解决方案1】:

Ondrej 的回答解释了如何解决在TIdFTP.MakeDir() 中处理 250 回复的问题。

请注意,TIdFTP.MakeDir() 只是 TIdTCPConnection.SendCmd() 的包装器:

procedure TIdFTP.MakeDir(const ADirName: string);
begin
  SendCmd('MKD ' + ADirName, 257); {do not localize}
end;

SendCmd()public,因此另一种解决方案是直接调用SendCmd() 并告诉它250 是可接受的回复代码:

s := TBytesStream.Create;
Try
  Field.SaveToStream(s);
  //MakeDir(TPath.GetDirectoryName(url));
  SendCmd('MKD ' + TPath.GetDirectoryName(url), [250, 257]);
  Put(s, url);
Finally
  s.Free;
End;

或者,要接受 any 2xx 回复代码,您可以这样做:

s := TBytesStream.Create;
Try
  Field.SaveToStream(s);
  //MakeDir(TPath.GetDirectoryName(url));
  if (SendCmd('MKD ' + TPath.GetDirectoryName(url)) div 100) <> 2 then
    RaiseExceptionForLastCmdResult;
  Put(s, url);
Finally
  s.Free;
End;

【讨论】:

  • 恕我直言,这是一个更好的解决方案。
  • 谢谢 Remy... 我知道你可能会加入 :) 这看起来确实更好。我注意到它是一个包装器,但并不是 SendCmd 是公开的。既然 Ondrej 同意这个更好,我会接受这个。
【解决方案2】:

EIdReplyRFCError 属性等于250 时,您可以只处理EIdReplyRFCError 的特定情况,在任何其他情况下重新加注。

s := TBytesStream.Create;
Try
  Field.SaveToStream(s);
  Try
    MakeDir(TPath.GetDirectoryName(url));
  Except
    on E: EIdReplyRFCError do
      if E.ErrorCode <> 250 then raise;
  end
  Put(s, url);
Finally
  s.Free;
End;

【讨论】:

  • 最好有一个 On... Else Raise; ?因为这个除了块不会重新引发其他类型的异常,对吧?我知道我应该对此更加确定......但我并不真正喜欢捕捉和处理异常。我只使用过 Try... 除了将内部异常重新映射到我然后立即引发的自定义类型。
  • "else raise" 是隐含的,即。任何未在“on”子句中列出的异常都不会被处理并将被引发。
  • @Frazz 如果except 没有on 语句,它会捕获所有异常。如果excepton 语句,那么这些是它捕获的唯一异常类型。未捕获的异常不需要重新引发,因为它们会自动继续调用堆栈寻找匹配的except
猜你喜欢
  • 2014-11-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多