HTTP POST renvoie l'erreur: 417 «Échec de l'attente».


212

Lorsque j'essaie de POSTER vers une URL, il en résulte l'exception suivante:

Le serveur distant a renvoyé une erreur: (417) Échec de l'attente.

Voici un exemple de code:

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.

Utiliser une HttpWebRequest/HttpWebResponsepaire ou un HttpClientne fait aucune différence.

Quelle est la cause de cette exception?


2
Le problème semble se produire lorsque votre application communique via un serveur proxy. Une application .NET que j'ai écrite fonctionnait lorsqu'elle était directement connectée à Internet, mais pas lorsqu'elle était derrière un serveur proxy.
Salman A

2
Observé cette condition lorsqu'un client s'exécute via un serveur proxy HTTP 1.0 (uniquement). Le client (proxy asmx sans aucune configuration) envoie une requête HTTP 1.1 et le proxy (avant qu'un serveur ne puisse jamais être impliqué) rejette ensuite ce que le proxy envoie. Un utilisateur final devrait avoir ce problème, en utilisant la solution de configuration ci - dessous est une solution de contournement appropriée car elle entraînerait des demandes de générer sans recours à la procuration compréhension de l' en- Expecttête qui , par défaut est ajouté comme Expect100Continueest truepar défaut.
Ruben Bartelink

Réponses:


478

System.Net.HttpWebRequest ajoute l'en-tête 'En-tête HTTP "Expect: 100-Continue"' à chaque demande, sauf si vous lui demandez explicitement de ne pas le faire en définissant cette propriété statique sur false:

System.Net.ServicePointManager.Expect100Continue = false;

Certains serveurs s'étouffent avec cet en-tête et renvoient l'erreur 417 que vous voyez.

Essayez ça.


5
J'ai eu un code qui a parlé à Twitter qui a soudainement cessé de fonctionner le lendemain de Noël. Ils avaient effectué une mise à niveau ou un changement de configuration qui avait provoqué l'étouffement de leurs serveurs sur cet en-tête. C'était difficile de trouver la solution.
xcud

8
Je pense que j'ai ramassé 10 points supplémentaires pour obtenir une réponse acceptée dans un fil dans lequel Jon Skeet a posté une solution.
xcud

1
Merci! Cela devrait être noté quelque part dans les exemples msdn tels que msdn.microsoft.com/en-us/library/debx8sh9.aspx
Eugene

25
Vous pouvez également spécifier cette propriété dans votre app.config: <system.net> <settings> <servicePointManager expect100Continue = "false" />. nahidulkibria.blogspot.com/2009/06/…
Andre Luus

2
Remarque: ce paramètre s'applique également aux ServiceReferences et je suppose que les WebReferences.
Myster

115

Autrement -

Ajoutez ces lignes à la section de configuration de votre fichier de configuration d'application:

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

6
Fonctionne très bien lorsque vous devez effectuer un changement opérationnel et que vous n'êtes pas prêt pour un changement de code.
dawebber

1
Que fait cette ligne de configuration?
J86

31

Cette même situation et cette erreur peuvent également survenir avec un proxy de service Web SOAP généré par assistant (pas à 100% si c'est également le cas sur la System.ServiceModelpile WCF ) lors de l'exécution:

  • la machine de l'utilisateur final est configurée (dans les paramètres Internet) pour utiliser un proxy qui ne comprend pas HTTP 1.1
  • le client finit par envoyer quelque chose qu'un proxy HTTP 1.0 ne comprend pas (généralement un en- Expecttête dans le cadre d'un HTTP POSTou d'une PUTdemande en raison d'une convention de protocole standard d'envoi de la demande en deux parties, comme indiqué dans les remarques ici )

... donnant un 417.

Comme indiqué dans les autres réponses, si le problème spécifique que vous rencontrez est que l'en- Expecttête est à l'origine du problème, ce problème spécifique peut être détourné en effectuant une désactivation relativement globale de la transmission PUT / POST en deux parties via System.Net.ServicePointManager.Expect100Continue.

Cependant, cela ne résout pas le problème sous-jacent complet - la pile peut toujours utiliser des choses spécifiques à HTTP 1.1 telles que KeepAlives etc. (bien que dans de nombreux cas, les autres réponses couvrent les cas principaux.)

Le problème réel est cependant que le code généré automatiquement suppose qu'il est OK d'utiliser aveuglément les fonctionnalités HTTP 1.1 comme tout le monde le comprend. Pour arrêter cette hypothèse pour un proxy de service Web spécifique, on peut modifier la substitution du sous-jacent par défaut HttpWebRequest.ProtocolVersionà la valeur par défaut de 1.1 en créant une classe de proxy dérivée qui remplace comme indiqué dans cet article : -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;
    }
}

(où MyWSest le proxy que l'assistant Ajouter une référence Web vous a craché.)


MISE À JOUR: Voici un implément que j'utilise en production:

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
Je sais que tu as posté ça il y a un bon moment, mais Ruben, tu sauves des vies. Ce problème m'a rendu fou jusqu'à ce que je tombe sur votre solution et cela fonctionne parfaitement. À votre santé!
Christopher McAtackney

1
@ChrisMcAtackney Vous êtes les bienvenus. Cela semblait vraiment valoir la peine de le documenter à ce moment-là ... le problème général se situait en marge de devenir un problème prioritaire et m'a juste dérangé jusqu'à ce que j'étudie correctement - mais il ne semblait pas y avoir de jus Google pour cet aspect de la question. et c'était l'un des messages de ce type d'Attwood qui m'avait poussé à le faire. (Un vote positif avec un commentaire comme celui-ci est fantastique BTW)
Ruben Bartelink

1
Magnifique ajout et exemples. Merci!
Fadi Chamieh

5

Le formulaire que vous essayez d'émuler comporte-t-il deux champs, nom d'utilisateur et mot de passe?

Si oui, cette ligne:

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

n'est pas correcte.

vous auriez besoin de deux lignes comme:

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

Éditer:

D'accord, puisque ce n'est pas le problème, une façon de résoudre ce problème consiste à utiliser quelque chose comme Fiddler ou Wireshark pour regarder avec succès ce qui est envoyé au serveur Web à partir du navigateur, puis comparer cela à ce qui est envoyé à partir de votre code. Si vous allez sur un port 80 normal à partir de .Net, Fiddler capturera toujours ce trafic.

Il y a probablement un autre champ caché sur le formulaire que le serveur Web attend que vous n'envoyez pas.


3

Solution du côté proxy, j'ai rencontré des problèmes dans le processus de négociation SSL et j'ai dû forcer mon serveur proxy à envoyer des demandes à l'aide de HTTP / 1.0 pour résoudre le problème en définissant cet argument dans le httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1après avoir rencontré l'erreur 417 comme mon application cliente utilisait HTTP / 1.1 et le proxy a été forcé d'utiliser HTTP / 1.0, le problème a été résolu en définissant ce paramètre dans httpd.conf du côté proxy RequestHeader unset Expect earlysans avoir besoin de changer quoi que ce soit du côté client, espérons que cela aide .


2

Pour Powershell, c'est

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

1

Si vous utilisez " HttpClient " et que vous ne souhaitez pas utiliser la configuration globale pour affecter tout votre programme, vous pouvez utiliser:

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

Si vous utilisez " WebClient ", je pense que vous pouvez essayer de supprimer cet en-tête en appelant:

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

0

Dans ma situation, cette erreur semble se produire uniquement si l'ordinateur de mon client a une politique de pare-feu stricte, ce qui empêche mon programme de communiquer avec le service Web.

La seule solution que j'ai pu trouver consiste donc à détecter l'erreur et à informer l'utilisateur de la modification manuelle des paramètres du pare-feu.


-1

L'approche web.config fonctionne pour les appels de services de formulaire InfoPath aux règles activées du service Web IntApp.

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

2
dup of stackoverflow.com/a/7358457/11635 Veuillez commenter ici si vous voulez ajouter un point
Ruben Bartelink
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.