web-dev-qa-db-ja.com

HttpRequestException-これはクライアントまたはサーバーの問題ですか?

少し前に、HttpClientクラスを使用してREST Apiを使用するコードを実装しました。

using (var client = new HttpClient() { BaseAddress = new Uri(@"https://thirdparty.com") })
{
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(...);

    var uri = new Uri(@"rest/api/foo", UriKind.Relative);
    var content = new StringContent(json.ToString());

    using (var response = await client.PostAsync(uri, content))
    {
        // etc ...
    }
}

このコードは、テスト環境と本番環境(それぞれがテスト/本番uriにアクセスする)の両方に対して完全に正常に機能しているように見えました。最近、本番環境のみでHttpRequestExceptionが発生し始めました:System.Net.Http.HttpRequestException: Error while copying content to a stream.

これは少し奇妙に思えたので、Postmanを使用して同じメッセージを送信しましたが、問題なく機能しました。コードが失敗し、Postmanが機能していた理由がわかりませんでした。 jsonデータのパラメーター(状態を「NY」から「NV」)に変更したところ、.NETコードは正常に機能しました。もちろん、間違ったjsonデータを送信することはできないため、これは解決策ではありません。これは、まったく同じコードが異なるコンテンツで正常に機能するという観察結果でした。


興味深いのは、これを解決するために行うことができる2つのコード変更があることです。まず、Postmanは RestSharp パッケージを使用して動作するC#コードを生成できます。または、HttpVersion 1.0の使用を指す別の質問から answer を見つけました。

using (var request = new HttpRequestMessage(HttpMethod.Post, uri))
{
    request.Version = HttpVersion.Version10;
    request.Content = new StringContent(json.ToString());

    using (var response = await client.SendAsync(request))
    {
        // etc ...
    }
}

紛らわしいのは、PostmanがHTTP /1.1バージョンを使用していることです。したがって、要約すると:

  • Jsonデータ(米国の州を「NY」から「NV」に変更)を変更すると、コードは機能します。
  • 同じ正確なjsonとコードがテストuriに対して機能します。
  • RestSharpパッケージを使用するようにコードを変更すると機能します。
  • HTTP /1.1の代わりにHTTP/1.0を使用するようにコードを変更すると機能します。

いったいなぜPostmanはHTTP/1.1を使用して作業できるのに、HttpClientが失敗するのでしょうか。これは私たちのクライアントの問題ですか(コードは他の米国の州で機能します)?これは.NETFrameworkのバグですか?サードパーティからのREST Apiの実装/ホスティングに何か問題がありますか?


郵便配達員のヘッダー:

POST rest/api/foo HTTP/1.1
Host: thirdparty.com
Content-Type: application/json
Authorization: Basic SOME_ENCRYPTED_USER_PASS
Cache-Control: no-cache
Postman-Token: 2fa5b5a0-b5d3-bd4c-40f0-d2b55b60316b

サンプルJson:

{
    "stateCode": "NY",
    "packageID": "58330",
    "name": "58330-PRI-1",
    "documents": [
        {
            "type": "SPECIAL",
            "name": "Sample Document",
            "documentID": "3569976"
        }
    ],
    "descriptions": [
        {
            "city": "New York",
            "state": "NY"
        }
    ]
}

スタックトレース:

AggregateException: One or more errors occured.
HttpRequestException: Error while copying content to a stream.
IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote Host.
SocketException: An existing connection was forcibly closed by the remote Host.
22
m-y

データを少し変更して成功させることができるという事実のために、あなたの問題はあなたのコードとは何の関係もないと思います。サーバーが不正な値をキャッシュし、キャッシュがクリアされるまでその値を送信し続ける場合はどうなりますか?

キャッシュされた値を使用しないようにサーバーに暗黙的に指示してみてください...

using (var client = new HttpClient() { BaseAddress = new Uri(@"https://thirdparty.com") })
{
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(...);

    var uri = new Uri(@"rest/api/foo", UriKind.Relative);
    var content = new StringContent(json.ToString());

    client.DefaultRequestHeaders.CacheControl = CacheControlHeaderValue.Parse("no-cache");

    using (var response = await client.PostAsync(uri, content))
    {
        // etc ...
    }
}

有効な応答ストリームを取得するかどうかを確認します。

1
Larry Dukek

HttpClientを実行しているマシンにアンチウイルス/ファイアウォールがありますか?私は過去に、AVG、McAfee、Nortonなどがサイレントにリクエストをブロックすることに問題がありました。正確な場所を見つけるのは非常に難しいですが、ポートを監視するタブがある場合があります。これをオフ/無効にすると、問題の特定に役立つ場合があります。その場合、適切な解決策は、適切なベンダーのホワイトリストに「thirdparty.com」を掲載することです。

サーバーからの応答ヘッダーも確認する価値があるかもしれません。それらを質問に追加できますか?過去に、Content-Security-Policyヘッダーが原因で、一部のリクエストが完了できないことがわかったからです。

0
Dai Bok