HTTP POST gibt Fehler zurück: 417 "Erwartung fehlgeschlagen."

212

Wenn ich versuche, auf eine URL zu posten, führt dies zu der folgenden Ausnahme:

Der Remote-Server hat einen Fehler zurückgegeben: (417) Erwartung fehlgeschlagen.

Hier ist ein Beispielcode:

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.

Die Verwendung eines HttpWebRequest/HttpWebResponsePaares oder eines HttpClientmacht keinen Unterschied.

Was verursacht diese Ausnahme?

Saeb Amini
quelle
2
Das Problem scheint aufzutreten, wenn Ihre Anwendung über einen Proxyserver kommuniziert. Eine von mir geschriebene .NET-Anwendung funktionierte, wenn sie direkt mit dem Internet verbunden war, aber nicht, wenn sie sich hinter einem Proxyserver befand.
Salman A
2
Dieser Zustand wurde beobachtet, wenn ein Client über einen (nur) HTTP 1.0-Proxyserver ausgeführt wird. Der Client (asmx-Proxy ohne Konfiguration) sendet eine HTTP 1.1-Anforderung, und der Proxy (bevor ein Server jemals beteiligt werden könnte) lehnt dann ab, was der Proxy sendet. Sollte ein Endbenutzer dieses Problem haben, ist die Verwendung der folgenden Konfigurationslösung eine geeignete Problemumgehung, da dadurch Anforderungen generiert werden, ohne dass der Proxy den ExpectHeader versteht, der standardmäßig wie standardmäßig hinzugefügt Expect100Continuewird true.
Ruben Bartelink

Antworten:

478

System.Net.HttpWebRequest fügt jeder Anforderung den Header 'HTTP-Header "Expect: 100-Continue"' hinzu, es sei denn, Sie fordern dies ausdrücklich nicht an, indem Sie diese statische Eigenschaft auf false setzen:

System.Net.ServicePointManager.Expect100Continue = false;

Einige Server ersticken an diesem Header und senden den angezeigten 417-Fehler zurück.

Probieren Sie es aus.

xcud
quelle
5
Ich hatte einen Code, der mit Twitter sprach und am Tag nach Weihnachten plötzlich nicht mehr funktionierte. Sie hatten ein Upgrade oder eine Konfigurationsänderung vorgenommen, die dazu führte, dass ihre Server an diesem Header erstickten. Es war ein Schmerz, die Lösung zu finden.
xcud
8
Ich glaube, ich habe zusätzliche 10 Punkte gesammelt, um eine Antwort in einem Thread zu erhalten, in den Jon Skeet eine Lösung gepostet hat.
Xcud
1
Vielen Dank! Dies sollte irgendwo in msdn-Beispielen wie msdn.microsoft.com/en-us/library/debx8sh9.aspx
Eugene
25
Sie können diese Eigenschaft auch in Ihrer app.config angeben: <system.net> <settings> <servicePointManager expected100Continue = "false" />. nahidulkibria.blogspot.com/2009/06/…
Andre Luus
2
Hinweis: Diese Einstellung gilt auch für ServiceReferences und ich gehe von WebReferences aus.
Myster
114

Ein anderer Weg -

Fügen Sie diese Zeilen zum Konfigurationsabschnitt Ihrer Anwendungskonfigurationsdatei hinzu:

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>
Engin Ardıç
quelle
6
Funktioniert sehr gut, wenn Sie eine betriebliche Änderung vornehmen müssen und nicht für eine Codeänderung bereit sind.
Dawebber
1
Was macht diese Konfigurationszeile?
J86
31

Dieselbe Situation und dieser Fehler können auch bei einem vom Standardassistenten generierten SOAP-Webdienst-Proxy (nicht 100%, wenn dies auch auf dem WCF- System.ServiceModelStapel der Fall ist ) zur Laufzeit auftreten:

  • Der Endbenutzercomputer ist (in den Interneteinstellungen) so konfiguriert, dass er einen Proxy verwendet, der HTTP 1.1 nicht versteht
  • Der Client sendet am Ende etwas, das ein HTTP 1.0-Proxy nicht versteht (normalerweise ein ExpectHeader als Teil eines HTTP POSToder einer PUTAnforderung aufgrund einer Standardprotokollkonvention zum Senden der Anforderung in zwei Teilen, wie in den Anmerkungen hier beschrieben ).

... ergibt eine 417.

Wie in den anderen Antworten beschrieben, kann das spezifische Problem, wenn Sie darauf stoßen, dass der ExpectHeader das Problem verursacht, durch ein relativ globales Abschalten der zweiteiligen PUT / POST-Übertragung über umgeleitet werden System.Net.ServicePointManager.Expect100Continue.

Dies behebt jedoch nicht das vollständige zugrunde liegende Problem - der Stack verwendet möglicherweise immer noch HTTP 1.1-spezifische Dinge wie KeepAlives usw. (obwohl in vielen Fällen die anderen Antworten die Hauptfälle abdecken.)

Das eigentliche Problem ist jedoch, dass der automatisch generierte Code davon ausgeht, dass es in Ordnung ist, HTTP 1.1-Funktionen blind zu verwenden, da dies jeder versteht. Um diese Annahme für einen bestimmten Webdienst-Proxy zu beenden, können Sie die Überschreibung der zugrunde liegenden Standardeinstellung HttpWebRequest.ProtocolVersionvon der Standardeinstellung 1.1 ändern, indem Sie eine abgeleitete Proxy-Klasse erstellen, die wie in diesem Beitrag gezeigt überschreibt : -protected override WebRequest GetWebRequest(Uri uri)

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

(Wo MyWSist der Proxy, den der Assistent zum Hinzufügen von Webreferenzen auf Sie ausgespuckt hat?)


UPDATE: Hier ist ein Gerät, das ich in der Produktion verwende:

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 };
    }
}
Ruben Bartelink
quelle
2
Ich weiß, dass du das vor einiger Zeit gepostet hast, aber Ruben, du bist ein Lebensretter. Dieses Problem hat mich verrückt gemacht, bis ich auf Ihre Lösung gestoßen bin und es perfekt funktioniert. Prost!
Christopher McAtackney
1
@ ChrisMcAtackney Gern geschehen. Es schien definitiv die Mühe wert zu sein, es zu diesem Zeitpunkt zu dokumentieren ... das allgemeine Problem, das sich am Rande eines Problems mit höchster Priorität befand und mich nur störte, bis ich es richtig untersuchte - aber es schien keinen Google-Saft dafür zu geben diese Seite des Problems. und es war einer der Posten dieses Attwood-Mannes von früher, der mich dazu drängte, es zu tun. (Eine positive Bewertung mit einem Kommentar wie diesem ist übrigens fantastisch)
Ruben Bartelink
1
Wunderbare Ergänzung und Beispiele. Vielen Dank!
Fadi Chamieh
5

Hat das Formular, das Sie emulieren möchten, zwei Felder, Benutzername und Passwort?

Wenn ja, diese Zeile:

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

das ist nicht richtig.

Sie würden zwei Zeilen benötigen wie:

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

Bearbeiten:

Okay, da dies nicht das Problem ist, besteht eine Möglichkeit, dies zu beheben, darin, mithilfe von Fiddler oder Wireshark zu beobachten, was vom Browser erfolgreich an den Webserver gesendet wird, und dies dann mit dem zu vergleichen, was von Ihrem Code gesendet wird. Wenn Sie von .Net zu einem normalen Port 80 wechseln, erfasst Fiddler diesen Datenverkehr weiterhin.

Es gibt wahrscheinlich ein anderes verstecktes Feld im Formular, das der Webserver erwartet, dass Sie nicht senden.

Elch
quelle
3

Lösung von der Proxyseite, ich hatte einige Probleme beim SSL-Handshake-Prozess und musste meinen Proxyserver zwingen, Anforderungen über HTTP / 1.0 zu senden, um das Problem zu lösen, indem SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1ich dieses Argument in der httpd.conf festlegte. Danach trat der Fehler 417 als auf Meine Client-Anwendung verwendete HTTP / 1.1 und der Proxy musste HTTP / 1.0 verwenden. Das Problem wurde behoben, indem dieser Parameter in der httpd.conf auf der Proxy-Seite festgelegt wurde, RequestHeader unset Expect earlyohne dass auf der Client-Seite Änderungen vorgenommen werden mussten. Ich hoffe, dies hilft .

Hytham
quelle
2

Für Powershell ist es das

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

Wenn Sie " HttpClient " verwenden und keine globale Konfiguration verwenden möchten, um alles zu beeinflussen, was Sie programmieren können:

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

Wenn Sie " WebClient " verwenden, können Sie versuchen, diesen Header zu entfernen, indem Sie Folgendes aufrufen:

 var client = new WebClient();
 client.Headers.Remove(HttpRequestHeader.Expect);
Aviram Fireberger
quelle
0

In meiner Situation scheint dieser Fehler nur aufzutreten, wenn der Computer meines Clients über eine strenge Firewall-Richtlinie verfügt, die verhindert, dass mein Programm mit dem Webdienst kommuniziert.

Die einzige Lösung, die ich finden konnte, besteht darin, den Fehler abzufangen und den Benutzer über das manuelle Ändern der Firewall-Einstellungen zu informieren.

Emre Can Serteli
quelle
-1

Der web.config-Ansatz funktioniert für InfoPath-Formulardienstaufrufe an Regeln, die für IntApp-Webdienste aktiviert sind.

  <system.net>
    <defaultProxy />
    <settings> <!-- 20130323 bchauvin -->
        <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>
BobC
quelle
2
dup of stackoverflow.com/a/7358457/11635 Bitte kommentieren Sie dort, wenn Sie einen Punkt hinzufügen möchten
Ruben Bartelink