【问题标题】:How to make an HTTP request in a separate thread with timeout?如何在具有超时的单独线程中发出 HTTP 请求?
【发布时间】:2011-01-28 21:57:20
【问题描述】:

我已经有一段时间没有在 Delphi 中编程了,坦率地说,我认为我永远不需要,但是...... 我在这里,拼命地想找到一些关于这件事的信息,而现在它是如此稀缺,我什么也找不到。所以也许你们可以帮助我。

目前我的应用程序使用 Synapse 库进行 HTTP 调用,但它不允许设置超时。通常,这不是什么大问题,但现在我绝对必须有一个超时才能很好地处理任何连接问题。

我正在寻找的是一个库(同步或非同步),它允许 HTTP 请求对用户完全透明,没有可见或隐藏的延迟。我现在不能立即杀死一个线程,并且有可能向服务器发出许多频繁的请求而没有响应,这不好。

编辑:感谢大家的回答!

【问题讨论】:

    标签: delphi http timeout multithreading request


    【解决方案1】:

    在进行网络通信时,您总是需要考虑延迟和超时。恕我直言,最接近的是将网络通信放在一个线程中。然后您可以检查线程是否在所需的时间完成,如果不让它完成,而是忽略结果(没有安全的方法来中止线程)。这还有一个额外的优势:您现在可以只使用更易于阅读的同步网络调用。

    【讨论】:

    • Synapse 在线程中工作正常,并且支持超时,这实际上是对标准函数进行更改以在底层对象上设置适当的属性。
    • 好的,就这样吧。然后我将继续使用带有 GsvThread 管理器的 Synapse,看看它的性能如何。
    【解决方案2】:

    synapse 中,超时可从TSynaClient 对象获得,THttpSend 来自该对象。因此,您所要做的调整超时(假设您使用标准函数)就是复制您使用的函数,添加一个新参数并将超时设置为您需要的值。例如:

    function HttpGetTextTimeout(const URL: string; 
                                const Response: TStrings;
                                const Timeout:integer): Boolean;
    var
      HTTP: THTTPSend;
    begin
      HTTP := THTTPSend.Create;
      try
        HTTP.Timeout := Timeout;
        Result := HTTP.HTTPMethod('GET', URL);
        if Result then
          Response.LoadFromStream(HTTP.Document);
      finally
        HTTP.Free;
      end;
    end;
    

    Synapse 默认超时为 5000,如果您等待的时间足够长,它会超时。由于其紧密包含,突触在线程中运行得非常好。

    【讨论】:

    【解决方案3】:

    [已知仅适用于 D2010]

    您可以使用 MSXML 发送客户端请求(将 msxmlole2 添加到您的 uses 子句中)。诀窍是使用 IServerXMLHTTPRequest 而不是 IXMLHTTPRequest,因为前者允许指定超时。下面的代码展示了一个线程的Execute()方法:

    procedure TClientSendThread.Execute;
    const
      LResolveTimeoutMilliseconds = 2000;
      LConnectTimeoutMilliseconds = 5000;
      LSendTimeoutMilliseconds = 5000;
      LReceiveTimeoutMilliseconds = 10000;
    var
      LHTTPServer: IServerXMLHTTPRequest;
      LDataStream: TMemoryStream;
      LData: OleVariant;
    begin
      {Needed because this is inside a thread.}
      CoInitialize(nil);
      LDataStream := TMemoryStream.Create;
      try
        {Populate ....LDataStream...}
        LData := MemoryStreamToOleVariant(LDataStream);
    
        LHTTPServer := CreateOleObject('MSXML2.ServerXMLHTTP.3.0') as IServerXMLHTTPRequest;
        LHTTPServer.setTimeouts(
          LResolveTimeoutMilliseconds,
          LConnectTimeoutMilliseconds,
          LSendTimeoutMilliseconds,
          LReceiveTimeoutMilliseconds
          );
        LHTTPServer.open('POST', URL, False, 0, 0);
        LHTTPServer.send(LData);
        FAnswer := LHTTPServer.responseText;
      finally
        FreeAndNil(LDataStream);
        CoUninitialize;
      end;
    end;
    

    我最近发现了这种 MSXML 技术的一个非常烦人的行为,如果后续发送的 URL 保持不变,GET 请求将不会被重新发送;换句话说,客户端正在缓存GET 请求。 POST 不会发生这种情况。

    显然,一旦发生超时,Execute 方法就会完成并清理线程。

    【讨论】:

    • 此代码 sn-p 在 D2007 中无法编译。它仅适用于更高版本的 Delphi 吗?问候,彼得
    • 是的,我认为带有 D2007 的 MSXML 版本不知道 ServerXMLHTTP。我确实记得有一些问题,抱歉没有提到它。帖子已编辑以指出这一点。
    【解决方案4】:

    可以将 Synapse 配置为在发生网络错误时引发异常。

    RaiseExcept

    查看http://synapse.ararat.cz/doc/help/blcksock.TBlockSocket.html#RaiseExcept:

    如果为 True,则引发 winsock 错误 例外。否则设置 仅限 LastError 值,您必须 从您的程序中检查它!默认 值为 False。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-24
      • 2018-07-16
      • 1970-01-01
      • 1970-01-01
      • 2020-03-14
      • 2017-12-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多