Errore di restituzione POST HTTP: 417 "Aspettativa fallita."


212

Quando provo a POST su un URL, si verifica la seguente eccezione:

Il server remoto ha restituito un errore: (417) Aspettativa non riuscita.

Ecco un codice di esempio:

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.

Usare una HttpWebRequest/HttpWebResponsecoppia o una HttpClientnon fa differenza.

Cosa sta causando questa eccezione?


2
Il problema sembra verificarsi quando l'applicazione comunica tramite un server proxy. Un'applicazione .NET che ho scritto ha funzionato quando era direttamente connessa a Internet ma non quando si trovava dietro un server proxy.
Salman A

2
Questa condizione è stata osservata quando un client è in esecuzione attraverso un server proxy HTTP 1.0 (solo). Il client (proxy asmx senza alcuna configurazione) sta inviando una richiesta HTTP 1.1 e il proxy (prima che qualsiasi server possa essere coinvolto) quindi rifiuta ciò su cui il proxy invia. Se un utente finale avere questo problema, utilizzando la soluzione di configurazione sotto è una soluzione appropriata poichè causerebbe richieste vengano generati senza dipendenza proxy comprensione della Expectintestazione che di default viene aggiunto come Expect100Continueè truepredefinita.
Ruben Bartelink,

Risposte:


478

System.Net.HttpWebRequest aggiunge l'intestazione 'HTTP header 'Expect: 100-Continue'' ad ogni richiesta a meno che non si chiede esplicitamente di non impostando questa proprietà statica su false:

System.Net.ServicePointManager.Expect100Continue = false;

Alcuni server soffocano su quell'intestazione e restituiscono l'errore 417 che stai vedendo.

Provaci.


5
Avevo del codice che parlava con Twitter e improvvisamente ha smesso di funzionare il giorno dopo Natale. Avevano fatto un aggiornamento o una modifica di configurazione che avevano causato i loro server a soffocare su quell'intestazione. È stato doloroso trovare la soluzione.
xcud,

8
Penso di aver raccolto altri 10 punti per ottenere una risposta accettata in una discussione in cui Jon Skeet ha pubblicato una soluzione.
xcud

1
Grazie! Questo dovrebbe essere notato da qualche parte negli esempi di msdn
Eugene

25
Puoi anche specificare quella proprietà nel tuo app.config: <system.net> <settings> <servicePointManager awa100Continue = "false" />. nahidulkibria.blogspot.com/2009/06/…
Andre

2
Nota: questa impostazione si applica anche a ServiceReferences e presumo WebReferences.
Myster,

115

Un altro modo -

Aggiungi queste righe alla sezione di configurazione del file di configurazione dell'applicazione:

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>

6
Funziona molto bene quando è necessario apportare una modifica operativa e non si è pronti per una modifica del codice.
dawebber,

1
Cosa fa quella linea di configurazione?
J86,

31

La stessa situazione ed errore possono verificarsi anche con una procedura guidata predefinita generata dal proxy del servizio Web SOAP (non al 100% se questo è anche il caso nello System.ServiceModelstack WCF ) durante l'esecuzione:

  • il computer dell'utente finale è configurato (nelle Impostazioni Internet) per utilizzare un proxy che non comprende HTTP 1.1
  • il client finisce per inviare qualcosa che un proxy HTTP 1.0 non comprende (di solito Expectun'intestazione come parte di un HTTP POSTo una PUTrichiesta a causa di una convenzione di protocollo standard di invio della richiesta in due parti come descritto nelle Note qui )

... dando un 417.

Come spiegato nelle altre risposte, se il problema specifico riscontrato è che l' Expectintestazione sta causando il problema, allora quel problema specifico può essere risolto eseguendo uno spegnimento relativamente globale della trasmissione PUT / POST in due parti tramite System.Net.ServicePointManager.Expect100Continue.

Tuttavia, ciò non risolve il problema di fondo completo: lo stack potrebbe ancora utilizzare cose specifiche di HTTP 1.1 come KeepAlives ecc. (Sebbene in molti casi le altre risposte coprano i casi principali).

Il vero problema è tuttavia che il codice generato automaticamente presuppone che sia OK utilizzare ciecamente le funzionalità HTTP 1.1 poiché tutti lo capiscono. Per interrompere questo presupposto per uno specifico proxy del servizio Web, è possibile modificare la sostituzione del valore predefinito sottostante HttpWebRequest.ProtocolVersionrispetto al valore predefinito di 1.1 creando una classe proxy derivata che sostituisce come mostrato in questo post : -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;
    }
}

(dov'è MyWSil proxy che la procedura guidata Aggiungi riferimento Web ti ha inviato.)


AGGIORNAMENTO: Ecco un impl che sto usando in produzione:

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

2
So che l'hai pubblicato abbastanza tempo fa, ma Ruben, sei un salvavita. Questo problema mi ha fatto impazzire fino a quando non ho trovato la tua soluzione e funziona perfettamente. Saluti!
Christopher McAtackney,

1
@ChrisMcAtackney Prego. Sicuramente ne è valsa la pena di documentarlo a loro tempo ... il problema generale posto attorno ai margini di diventare un problema di massima priorità e mi ha solo dato fastidio fino a quando non ho investigato correttamente - eppure non sembrava esserci alcun succo di Google per quella parte del problema. ed è stato uno dei post di quel tipo di Attwood che mi ha spinto a farlo. (Un voto con un commento come questo è fantastico BTW)
Ruben Bartelink il

1
Aggiunta ed esempi meravigliosi. Grazie!
Fadi Chamieh

5

Il modulo che stai tentando di emulare ha due campi, nome utente e password?

In tal caso, questa riga:

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

non è corretto.

avresti bisogno di due righe come:

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

Modificare:

Ok, dato che non è questo il problema, un modo per affrontarlo è usare qualcosa come Fiddler o Wireshark per guardare con successo ciò che viene inviato al server Web dal browser, quindi confrontarlo con ciò che viene inviato dal tuo codice. Se vai su una normale porta 80 da .Net, Fiddler acquisirà comunque questo traffico.

Probabilmente c'è un altro campo nascosto nel modulo che il server Web prevede di non inviare.


3

Soluzione dal lato proxy, ho riscontrato alcuni problemi nel processo di handshake SSL e ho dovuto forzare il mio server proxy a inviare richieste utilizzando HTTP / 1.0 per risolvere il problema impostando questo argomento in httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1dopo che ho riscontrato l'errore 417 come l'applicazione client utilizzava HTTP / 1.1 e il proxy è stato costretto a utilizzare HTTP / 1.0, il problema è stato risolto impostando questo parametro in httpd.conf sul lato proxy RequestHeader unset Expect earlysenza la necessità di modificare nulla sul lato client, spero che questo aiuti .


2

Per Powershell lo è

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

1

Se si utilizza " HttpClient " e non si desidera utilizzare la configurazione globale per influire su tutto il programma, è possibile utilizzare:

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

Se stai usando " WebClient " penso che puoi provare a rimuovere questa intestazione chiamando:

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

0

Nella mia situazione, questo errore sembra verificarsi solo se il computer del mio client ha una rigorosa politica firewall, che impedisce al mio programma di comunicare con il servizio web.

Quindi l'unica soluzione che ho trovato è quella di rilevare l'errore e informare l'utente sulla modifica manuale delle impostazioni del firewall.


-1

L'approccio web.config funziona per le chiamate dei servizi del modulo di InfoPath alle regole abilitate al servizio Web di IntApp.

  <system.net>
    <defaultProxy />
    <settings> <!-- 20130323 bchauvin -->
        <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>

2
dup of stackoverflow.com/a/7358457/11635 Si prega di commentare lì se si desidera aggiungere un punto
Ruben Bartelink
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.