【问题标题】:GetRequestStream() is throwing time out exception when posting data to HTTPS url将数据发布到 HTTPS url 时,GetRequestStream() 抛出超时异常
【发布时间】:2012-03-26 12:38:40
【问题描述】:

我正在调用托管在 Apache 服务器上的 API 来发布数据。我正在使用 HttpWebRequest 在 C# 中执行 POST。

API 在服务器上同时具有普通 HTTP 和安全层 (HTTPS) 端口。当我调用 HTTP URL 时,它工作得很好。但是,当我调用 HTTPS 时,它会给我超时异常(在 GetRequestStream() 函数中)。有什么见解吗?我正在使用 VS 2010、.Net 框架 3.5 和 C#。这是代码块:

string json_value = jsonSerializer.Serialize(data);


        HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create("https://server-url-xxxx.com");
        request.Method = "POST";
        request.ProtocolVersion = System.Net.HttpVersion.Version10;
        request.ContentType = "application/x-www-form-urlencoded";

        byte[] buffer = Encoding.ASCII.GetBytes(json_value);
        request.ContentLength = buffer.Length;
        System.IO.Stream reqStream = request.GetRequestStream();
        reqStream.Write(buffer, 0, buffer.Length);
        reqStream.Close();

编辑: Peter 建议的控制台程序运行良好。但是当我添加需要发布到 API 的数据(JSON 格式)时,它会抛出操作超时异常。这是我添加到基于控制台的应用程序的代码,它会引发错误。

byte[] buffer = Encoding.ASCII.GetBytes(json_value);
request.ContentLength = buffer.Length;

【问题讨论】:

  • 你可以在没有 ProtocolVersion 和 ContentType 的情况下试试吗
  • 还可以使用wireshark 看看网络上发生了什么。检查目标服务器是否接受跨域调用。
  • 谢谢彼得。我添加了 ProtocolVersion 和 ContentType,但看起来并没有太大帮助。我将使用 wireshark 进行检查,但由于 Python 应用程序可以轻松 GET/POST 到 API,我相信服务器正在接受跨域调用。

标签: c# asp.net-mvc post https httprequest


【解决方案1】:

我遇到了同样的问题。似乎它为我解决了。我检查了所有代码,确保为我的所有 HttpWebResponse 对象调用 webResponse.Close() 和/或 responseStream.Close()。文档表明您可以关闭流或 HttpWebResponse 对象。调用两者都无害,所以我做到了。不关闭响应可能会导致应用程序用尽连接以供重用,据我在代码中观察到,这似乎会影响 HttpWebRequest.GetRequestStream。

【讨论】:

  • 我在使用 REST API 进行 Azure 移动服务时发生了这种情况
  • 实际上,这与@Peter 接受的答案相同
【解决方案2】:

我不知道这是否会帮助您解决特定问题,但您应该考虑在完成这些对象后处理它们。我最近正在做类似的事情,并且在 using 语句中包装东西似乎为我清理了一堆超时异常。

            using (var reqStream = request.GetRequestStream())
            {
                if (reqStream == null)
                {
                    return;
                }

              //do whatever

            }

还要检查这些东西

  • 服务器是否在您的本地开发环境中提供 https 服务?
  • 您是否正确设置了绑定 *.443 (https)?
  • 您需要在请求中设置凭据吗?
  • 是你的应用池账号访问了https资源还是你的账号被通过了?
  • 您是否考虑过使用 WebClient 代替?

    using (WebClient client = new WebClient())
        {               
            using (Stream stream = client.OpenRead("https://server-url-xxxx.com"))
            using (StreamReader reader = new StreamReader(stream))
            {
                MessageBox.Show(reader.ReadToEnd());
            }
        }
    

编辑:

从控制台发出请求。

internal class Program
{
    private static void Main(string[] args)
    {
        new Program().Run();
        Console.ReadLine();
    }

    public void Run()
    {

       var request = (HttpWebRequest)System.Net.WebRequest.Create("https://server-url-xxxx.com");
        request.Method = "POST";
        request.ProtocolVersion = System.Net.HttpVersion.Version10;
        request.ContentType = "application/x-www-form-urlencoded";

        using (var reqStream = request.GetRequestStream())
        {
            using(var response = new StreamReader(reqStream )
            {
              Console.WriteLine(response.ReadToEnd());
            }
        }
    }
}

【讨论】:

  • 感谢您的回复。 1. 不,它没有服务 2. 是 3. 不 4. 你能详细说明一下吗?我没明白。 5. 我试过 WebClient 但在 .OpenRead 中它会抛出操作超时错误
  • 另一个更新 - 我已经设置了简单的 Python 应用程序以通过 HTTPS 访问相同的 API,并且它工作得非常好。所以看起来只有 .Net 是有问题的。不知道为什么。
  • 您运行的是 cassini、iisexpress 还是 iis?
  • 你可以在控制台应用程序中尝试一下吗?
  • 我在本地开发环境中运行这个应用程序。在卡西尼号上。很抱歉,这听起来可能很菜鸟,但是您如何在控制台应用程序中尝试呢?
【解决方案3】:

试试这个:

    WebRequest req = WebRequest.Create("https://server-url-xxxx.com");
    req.Method = "POST";
    string json_value = jsonSerializer.Serialize(data); //Body data
    ServicePointManager.Expect100Continue = false;
    using (var streamWriter = new StreamWriter(req.GetRequestStream()))
    {
        streamWriter.Write(json_value);
        streamWriter.Flush();
        streamWriter.Close();
    }
    HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
    Stream GETResponseStream = resp.GetResponseStream();
    StreamReader sr = new StreamReader(GETResponseStream);
    var response = sr.ReadToEnd(); //Response
    resp.Close(); //Close response
    sr.Close(); //Close StreamReader

并查看 URI:

  • 保留字符。通过URI发送保留字符可以带 问题! * ' ( ) ; : @ & = + $ , / ? # [ ]

  • URI 长度:不应超过 2000 个字符

【讨论】:

  • StreamWriter 将在其 Dispose() 方法中调用 Flush()Close(),该方法将为您的 using 块调用。
  • 非常感谢,关闭 Response 和 StreamReader 对我有用。
【解决方案4】:

我也遇到过这个。我想用控制台应用模拟数百个用户。当只模拟一个用户时,一切都很好。但随着用户的增多,Timeout 异常一直出现。

发生超时是因为默认情况下 ConnectionLimit=2 到 ServicePoint(又名网站)。 非常好的文章阅读:https://venkateshnarayanan.wordpress.com/2013/04/17/httpwebrequest-reuse-of-tcp-connections/

你可以做的是:

1) 在一个 servicePoint 中创建更多 ConnectionGroups,因为 ConnectionLimit 是每个 ConnectionGroups 的。

2) 或者你只是增加连接限制。

查看我的解决方案:

private HttpWebRequest CreateHttpWebRequest<U>(string userSessionID, string method, string fullUrl, U uploadData)
{
    HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(fullUrl);
    req.Method = method; // GET PUT POST DELETE
    req.ConnectionGroupName = userSessionID;  // We make separate connection-groups for each user session. Within a group connections can be reused.
    req.ServicePoint.ConnectionLimit = 10;    // The default value of 2 within a ConnectionGroup caused me always a "Timeout exception" because a user's 1-3 concurrent WebRequests within a second.
    req.ServicePoint.MaxIdleTime = 5 * 1000;  // (5 sec) default was 100000 (100 sec).  Max idle time for a connection within a ConnectionGroup for reuse before closing
    Log("Statistics: The sum of connections of all connectiongroups within the ServicePoint: " + req.ServicePoint.CurrentConnections; // just for statistics

    if (uploadData != null)
    {
        req.ContentType = "application/json";
        SerializeToJson(uploadData, req.GetRequestStream());
    }
    return req;
}

/// <summary>Serializes and writes obj to the requestStream and closes the stream. Uses JSON serialization from System.Runtime.Serialization.</summary>        
public void SerializeToJson(object obj, Stream requestStream)
{
    DataContractJsonSerializer json = new DataContractJsonSerializer(obj.GetType());
    json.WriteObject(requestStream, obj);            
    requestStream.Close();
}

【讨论】:

    【解决方案5】:

    【讨论】:

    • 感谢您的回复。我已经设置了,但还是不行。
    猜你喜欢
    • 2016-01-16
    • 2011-01-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-16
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多