C# 将数据发布到 HTTPS url 时,GetRequestStream() 抛出超时异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/9627669/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-09 08:15:51  来源:igfitidea点击:

GetRequestStream() is throwing time out exception when posting data to HTTPS url

c#asp.net-mvcposthttpshttprequest

提问by Wiz

I'm calling an API hosted on Apache server to post data. I'm using HttpWebRequest to perform POST in C#.

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

API has both normal HTTP and secure layer (HTTPS) PORT on the server. When I call HTTP URL it works perfectly fine. However, when I call HTTPS it gives me time-out exception (at GetRequestStream() function). Any insights? I'm using VS 2010, .Net framework 3.5 and C#. Here is the code block:

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();

EDIT: The console program suggested by Peter works fine. But when I add data (in JSON format) that needs to be posted to the API, it throws out operation timed out exception. Here is the code that I add to console based application and it throws error.

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

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

采纳答案by Peter

I don't know if this will help you with your specific problem but you should consider Disposing some of those objects when you are finished with them. I was doing something like this recently and wrapping stuff up in using statements seems to clean up a bunch of timeout exceptions for me.

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

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

              //do whatever

            }

also check these things

还要检查这些东西

  • Is the server serving https in your local dev environment?
  • Have you set up your bindings *.443 (https) properly?
  • Do you need to set credentials on the request?
  • Is it your application pool account accessing the https resources or is it your account being passed through?
  • Have you thought about using WebClient instead?

    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());
            }
        }
    
  • 服务器是否在您的本地开发环境中提供 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());
            }
        }
    

EDIT:

编辑:

make a request from console.

从控制台发出请求。

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());
            }
        }
    }
}

回答by seUser

回答by DDRider62

I ran into the same issue. It seems like it is solved for me. I went through all my code making sure to invoke webResponse.Close()and/or responseStream.Close()for all my HttpWebResponse objects. The documentation indicates that you can close the stream or the HttpWebResponse object. Calling both is not harmful, so I did. Not closing the responses may cause the application to run out of connections for reuse, and this seems to affect the HttpWebRequest.GetRequestStream as far as I can observe in my code.

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

回答by J.C. Gras

Try this:

尝试这个:

    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

And review the URI:

并查看 URI:

  • Reserved characters. Send reserved characters by the URI can bring problems ! * ' ( ) ; : @ & = + $ , / ? # [ ]

  • URI Length: You should not exceed 2000 characters

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

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

回答by FunRob

I ran into this, too. I wanted to simulate hundreds of users with a Console app. When simulating only one user, everything was fine. But with more users came the Timeout exception all the time.

我也遇到了这个。我想使用控制台应用程序模拟数百名用户。当只模拟一个用户时,一切都很好。但是随着越来越多的用户出现超时异常。

Timeout occurs because by default the ConnectionLimit=2 to a ServicePoint (aka website). Very good article to read: https://venkateshnarayanan.wordpress.com/2013/04/17/httpwebrequest-reuse-of-tcp-connections/

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

What you can do is:

你可以做的是:

1) make more ConnectionGroups within a servicePoint, because ConnectionLimit is per ConnectionGroups.

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

2) or you just simply increase the connection limit.

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

See my solution:

请参阅我的解决方案:

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();
}