web-dev-qa-db-ja.com

HTTP POSTがエラーを返します:417 "Expectation Failed。"

URLにPOSTしようとすると、次の例外が発生します。

リモートサーバーがエラーを返しました:(417)Expectation Failed。

サンプルコードを次に示します。

var client = new WebClient();

var postData = new NameValueCollection();
postData.Add("postParamName", "postParamValue");

byte[] responseBytes = client.UploadValues("http://...", postData);
string response = Encoding.UTF8.GetString(responseBytes); // (417) Expectation Failed.

HttpWebRequest/HttpWebResponseペアまたはHttpClientを使用しても違いはありません。

この例外の原因は何ですか?

208
Saeb Amini

System.Net.HttpWebRequestは、 this static property をfalseに設定することで明示的に要求しない限り、すべてのリクエストに 'HTTPヘッダー "Expect:100-Continue"'ヘッダーを追加します。

System.Net.ServicePointManager.Expect100Continue = false;

一部のサーバーはそのヘッダーで停止し、表示されている417エラーを送り返します。

それを試してみてください。

467
xcud

別の方法 -

次の行をアプリケーション構成ファイル構成セクションに追加します。

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>
113
Engin Ardıç

この同じ状況とエラーは、実行時にSOAP Webサービスプロキシ(これがWCF System.ServiceModelスタックにも当てはまる場合は100%ではありません)で生成されたデフォルトウィザードでも発生します。

  • エンドユーザーのマシンは、HTTP 1.1を理解しないプロキシを使用するように(インターネット設定で)設定されています
  • クライアントは、HTTP 1.0プロキシが理解できないものを送信することになります(通常、2つの部分でリクエストを送信する標準プロトコル規約により、HTTP ExpectまたはPOSTリクエストの一部としてのPUTヘッダー こちらの備考で説明

... 417を生成します。

他の回答で説明されているように、実行する特定の問題がExpectヘッダーが問題の原因である場合、その特定の問題は、_を介した2部構成のPUT/POST送信を比較的グローバルに切り替えることで回避できます System.Net.ServicePointManager.Expect100Continue

ただし、これは根本的な問題を完全に解決するものではありません-スタックは、KeepAlivesなどのHTTP 1.1固有のものをまだ使用している可能性があります(多くの場合、他の回答は主なケースをカバーしています)

しかし実際の問題は、自動生成されたコードが、誰もがこれを理解しているため、HTTP 1.1機能を盲目的に使用しても問題ないと想定していることです。特定のWebサービスプロキシのこの仮定を停止するには、 protected override WebRequest GetWebRequest(Uri uri) をオーバーライドする派生プロキシクラスを作成して、デフォルトの HttpWebRequest.ProtocolVersion をデフォルトの 1.1 からオーバーライドします。 _ この投稿に示されているように :-

public class MyNotAssumingHttp11ProxiesAndServersProxy : MyWS
{
    protected override WebRequest GetWebRequest(Uri uri)
    {
      HttpWebRequest request = (HttpWebRequest)base.GetWebRequest(uri);
      request.ProtocolVersion = HttpVersion.Version10;
      return request;
    }
}

MyWSは、Web参照の追加ウィザードがあなたに吐き出すプロキシです。)


更新:本番環境で使用している実装は次のとおりです。

class ProxyFriendlyXXXWs : BasicHttpBinding_IXXX
{
    public ProxyFriendlyXXXWs( Uri destination )
    {
        Url = destination.ToString();
        this.IfProxiedUrlAddProxyOverriddenWithDefaultCredentials();
    }

    // Make it squirm through proxies that don't understand (or are misconfigured) to only understand HTTP 1.0 without yielding HTTP 417s
    protected override WebRequest GetWebRequest( Uri uri )
    {
        var request = (HttpWebRequest)base.GetWebRequest( uri );
        request.ProtocolVersion = HttpVersion.Version10;
        return request;
    }
}

static class SoapHttpClientProtocolRealWorldProxyTraversalExtensions
{
    // OOTB, .NET 1-4 do not submit credentials to proxies.
    // This avoids having to document how to 'just override a setting on your default proxy in your app.config' (or machine.config!)
    public static void IfProxiedUrlAddProxyOverriddenWithDefaultCredentials( this SoapHttpClientProtocol that )
    {
        Uri destination = new Uri( that.Url );
        Uri proxiedAddress = WebRequest.DefaultWebProxy.GetProxy( destination );
        if ( !destination.Equals( proxiedAddress ) )
            that.Proxy = new WebProxy( proxiedAddress ) { UseDefaultCredentials = true };
    }
}
30
Ruben Bartelink

エミュレートしようとしているフォームには、ユーザー名とパスワードの2つのフィールドがありますか?

その場合、次の行:

 postData.Add("username", "password");

正しくありません。

次のような2行が必要です。

 postData.Add("username", "Moose");
postData.Add("password", "NotMoosespasswordreally");

編集:

さて、それは問題ではないので、これに取り組むための1つの方法は、FiddlerやWiresharkのようなものを使用して、ブラウザからWebサーバーに送信されるものを正常に監視し、それをコードから送信されるものと比較することです。 .Netから通常のポート80に移動する場合、Fiddlerは引き続きこのトラフィックをキャプチャします。

Webサーバーが送信していないと予期しているフォームには、おそらく他の非表示フィールドがあります。

5
Moose

プロキシ側からの解決策として、SSLハンドシェイクプロセスでいくつかの問題に直面し、httpd.conf SetEnv force-proxy-request-1.0 1SetEnv proxy-nokeepalive 1でこの引数を設定することにより、プロキシサーバーがHTTP/1.0を使用してリクエストを送信するように強制する必要がありました。クライアントアプリケーションがHTTP/1.1を使用しており、プロキシがHTTP/1.0を使用するように強制されたため、クライアント側で何も変更せずにプロキシ側RequestHeader unset Expect earlyのhttpd.confでこのパラメータを設定することで問題を解決しました。お役に立てれば。

3
Hytham

Powershellの場合は

[System.Net.ServicePointManager]::Expect100Continue = $false
2
TNT

HttpClient」を使用しており、グローバル構成を使用して、使用できるすべてのプログラムに影響を与えたくない場合:

 HttpClientHandler httpClientHandler = new HttpClientHandler();
 httpClient.DefaultRequestHeaders.ExpectContinue = false;

WebClient」を使用している場合、次の呼び出しでこのヘッダーを削除できると思います。

 var client = new WebClient();
 client.Headers.Remove(HttpRequestHeader.Expect);
1

私の状況では、このエラーは、クライアントのコンピューターに厳密なファイアウォールポリシーがある場合にのみ発生するようです。これにより、プログラムがWebサービスと通信できなくなります。

そのため、私が見つけることができる唯一の解決策は、エラーをキャッチし、ファイアウォール設定を手動で変更することをユーザーに通知することです。

0