web-dev-qa-db-ja.com

GetRequestStream()は、HTTPSURLにデータを投稿するときにタイムアウト例外をスローします

データを投稿するために、ApacheサーバーでホストされているAPIを呼び出しています。私はHttpWebRequestを使用してC#でPOSTを実行しています。

APIには、サーバー上に通常のHTTPポートとセキュアレイヤー(HTTPS)ポートの両方があります。 HTTP URLを呼び出すと、完全に正常に機能します。ただし、HTTPSを呼び出すと、タイムアウト例外が発生します(GetRequestStream()関数で)。何か洞察はありますか? VS 2010、.Net Framework 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();

編集:ピーターによって提案されたコンソールプログラムは正常に動作します。しかし、APIに投稿する必要のあるデータ(JSON形式)を追加すると、操作のタイムアウト例外がスローされます。これがコンソールベースのアプリケーションに追加したコードで、エラーがスローされます。

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

これがあなたの特定の問題に役立つかどうかはわかりませんが、それらを使い終わったら、それらのオブジェクトのいくつかを破棄することを検討する必要があります。私は最近このようなことをしていましたが、ステートメントを使用してまとめると、タイムアウトの例外がクリーンアップされたようです。

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

私は同じ問題に遭遇しました。それは私にとって解決されたようです。すべてのコードを調べて、すべてのHttpWebResponseオブジェクトに対してwebResponse.Close()および/またはresponseStream.Close()を呼び出すようにしました。ドキュメントには、ストリームまたはHttpWebResponseオブジェクトを閉じることができることが示されています。両方を呼び出すことは有害ではないので、私はしました。応答を閉じないと、アプリケーションで再利用のための接続が不足する可能性があります。これは、コードで確認できる限り、HttpWebRequest.GetRequestStreamに影響を与えるようです。

14
DDRider62

これを試して:

_    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文字を超えてはなりません

3
J.C. Gras

タイムアウトプロパティを設定することをお勧めします。ここで確認してください http://www.codeproject.com/Tips/69637/Setting-timeout-property-for-System-Net-WebClient

1
seUser

私もこれに出くわしました。コンソールアプリで何百人ものユーザーをシミュレートしたかったのです。 1人のユーザーだけをシミュレートした場合、すべてが正常でした。しかし、ユーザーが増えると、常にタイムアウト例外が発生しました。

デフォルトでは、ServicePoint(別名Webサイト)へのConnectionLimit = 2が原因でタイムアウトが発生します。読むのに非常に良い記事: https://venkateshnarayanan.wordpress.com/2013/04/17/httpwebrequest-reuse-of-tcp-connections/

あなたができることは:

1)ConnectionLimitはConnectionGroupsごとであるため、servicePoint内にさらに多くの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();
}
0
FunRob