HTTP POST devuelve el error: 417 "Expectativa fallida".

212

Cuando intento PUBLICAR en una URL, aparece la siguiente excepción:

El servidor remoto devolvió un error: (417) Expectativa fallida.

Aquí hay un código de muestra:

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.

Usar un HttpWebRequest/HttpWebResponsepar o un HttpClientno hace la diferencia.

¿Qué está causando esta excepción?

Saeb Amini
fuente
2
El problema parece suceder cuando su aplicación se comunica a través de un servidor proxy. Una aplicación .NET que escribí funcionaba cuando estaba directamente conectada a internet pero no cuando estaba detrás de un servidor proxy.
Salman A
2
Se observó esta condición cuando un cliente se ejecuta a través de un servidor proxy HTTP 1.0 (solo). El cliente (proxy asmx sin ninguna configuración) está enviando una solicitud HTTP 1.1 y el proxy (antes de que cualquier servidor pueda involucrarse) rechaza lo que envía el proxy. Si un usuario final tiene este problema, el uso de la solución de configuración a continuación es una solución alternativa adecuada, ya que provocaría que se generen solicitudes sin depender de que el proxy comprenda el Expectencabezado que, de forma predeterminada, se agrega como Expect100Continueestá truepor defecto.
Ruben Bartelink

Respuestas:

478

System.Net.HttpWebRequest agrega el encabezado 'Encabezado HTTP "Esperar: 100-Continuar"' a cada solicitud a menos que explícitamente le pida que no establezca esta propiedad estática en falso:

System.Net.ServicePointManager.Expect100Continue = false;

Algunos servidores se ahogan con ese encabezado y devuelven el error 417 que está viendo.

Dale una oportunidad.

xcud
fuente
55
Tenía un código que hablaba con Twitter que de repente dejó de funcionar el día después de Navidad. Habían realizado una actualización o cambio de configuración que hizo que sus servidores comenzaran a ahogarse en ese encabezado. Fue un dolor encontrar la solución.
xcud
8
Creo que recogí 10 puntos adicionales para obtener una respuesta aceptada en un hilo en el que Jon Skeet publicó una solución.
xcud
1
¡Gracias! Esto debería observarse en algún lugar de los ejemplos de msdn como msdn.microsoft.com/en-us/library/debx8sh9.aspx
Eugene
25
También puede especificar esa propiedad en su app.config: <system.net> <settings> <servicePointManager expect100Continue = "false" />. nahidulkibria.blogspot.com/2009/06/…
Andre Luus
2
Nota: esta configuración también se aplica a ServiceReferences y supongo que WebReferences.
Myster
114

De otra manera -

Agregue estas líneas a la sección de configuración del archivo de configuración de su aplicación:

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>
Engin Ardıç
fuente
66
Funciona muy bien cuando tiene que hacer un cambio operativo y no está listo para un cambio de código.
dawebber
1
¿Qué hace esa línea de configuración?
J86
31

Esta misma situación y error también pueden surgir con un proxy de servicio web SOAP generado por asistente predeterminado (no 100% si este es también el caso en la System.ServiceModelpila de WCF ) cuando está en tiempo de ejecución:

  • la máquina del usuario final está configurada (en la Configuración de Internet) para usar un proxy que no comprende HTTP 1.1
  • el cliente termina enviando algo que un proxy HTTP 1.0 no comprende (comúnmente un Expectencabezado como parte de un HTTP POSTo PUTsolicitud debido a una convención de protocolo estándar de enviar la solicitud en dos partes como se cubre en los Comentarios aquí )

... produciendo un 417.

Como se explica en las otras respuestas, si el problema específico con el que se encuentra es que el Expectencabezado está causando el problema, entonces ese problema específico se puede enrutar haciendo una desconexión relativamente global de la transmisión PUT / POST de dos partes a través de System.Net.ServicePointManager.Expect100Continue.

Sin embargo, esto no soluciona el problema subyacente completo: la pila aún puede estar usando cosas específicas de HTTP 1.1 como KeepAlives, etc. (aunque en muchos casos las otras respuestas cubren los casos principales).

Sin embargo, el problema real es que el código autogenerado supone que está bien usar ciegamente las funciones de HTTP 1.1, ya que todos entienden esto. Para detener esta suposición para un proxy de servicio web específico, uno puede cambiar anular el valor subyacente HttpWebRequest.ProtocolVersionpredeterminado del valor predeterminado de 1.1 creando una clase de proxy derivada que se anula como se muestra en esta publicación :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;
    }
}

(¿dónde MyWSestá el proxy que el asistente para agregar referencias web le escuchó?)


ACTUALIZACIÓN: Aquí hay un impl que estoy usando en producción:

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
fuente
2
Sé que publicaste esto hace bastante tiempo, pero Rubén, eres un salvavidas. Este problema me ha estado volviendo loco hasta que encontré su solución y funciona perfectamente. ¡Salud!
Christopher McAtackney
1
@ChrisMcAtackney De nada. Definitivamente, valió la pena el esfuerzo de documentarlo en ese momento ... el problema general surgió al margen de convertirse en un problema de alta prioridad y simplemente me molestó hasta que lo investigué correctamente, sin embargo, no parecía haber ningún jugo de Google para ese lado del problema. y fue una de las publicaciones de ese tipo Attwood desde hace mucho tiempo que me empujó a hacerlo. (Un voto positivo con un comentario como este es fantástico, por cierto)
Ruben Bartelink
1
Maravillosa adición y ejemplos. ¡Gracias!
Fadi Chamieh
5

¿El formulario que intenta emular tiene dos campos, nombre de usuario y contraseña?

Si es así, esta línea:

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

no es correcto.

necesitarías dos líneas como:

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

Editar:

De acuerdo, ya que ese no es el problema, una forma de abordar esto es usar algo como Fiddler o Wireshark para ver lo que se envía al servidor web desde el navegador con éxito, luego compararlo con lo que se envía desde su código. Si va a un puerto 80 normal desde .Net, Fiddler aún capturará este tráfico.

Probablemente haya algún otro campo oculto en el formulario que el servidor web espera que no envíe.

Alce
fuente
3

Solución del lado del proxy, enfrenté algunos problemas en el proceso de protocolo de enlace SSL y tuve que forzar a mi servidor proxy a enviar solicitudes usando HTTP / 1.0 para resolver el problema configurando este argumento en httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1después de eso, me enfrenté al error 417 como la aplicación de mis clientes estaba usando HTTP / 1.1 y el proxy se vio obligado a usar HTTP / 1.0, el problema se resolvió configurando este parámetro en httpd.conf en el lado del proxy RequestHeader unset Expect earlysin la necesidad de cambiar nada en el lado del cliente, espero que esto ayude .

Hytham
fuente
2

Para Powershell es

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

Si está utilizando " HttpClient " y no desea utilizar la configuración global para afectar a todos los programas que puede utilizar:

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

Si está utilizando " WebClient ", creo que puede intentar eliminar este encabezado llamando a:

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

En mi situación, este error parece ocurrir solo si la computadora de mi cliente tiene una estricta política de firewall, lo que impide que mi programa se comunique con el servicio web.

Entonces, la única solución que pude encontrar es detectar el error e informar al usuario sobre cómo cambiar la configuración del firewall manualmente.

Emre Can Serteli
fuente
-1

El enfoque web.config funciona para las llamadas de servicios de formulario de InfoPath a las reglas habilitadas del servicio web IntApp.

  <system.net>
    <defaultProxy />
    <settings> <!-- 20130323 bchauvin -->
        <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>
BobC
fuente
2
dup of stackoverflow.com/a/7358457/11635 Por favor, comente allí si desea agregar un punto
Ruben Bartelink