HTTP POST devuelve el error: 417 "Error de expectativa".

Resuelto Saeb Amini asked hace 15 años • 11 respuestas

Cuando intento PUBLICAR en una URL, se produce 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 avatar Feb 20 '09 00:02 Saeb Amini
Aceptado

System.Net.HttpWebRequest agrega el encabezado 'Encabezado HTTP "Esperar: 100-Continuar"' a cada solicitud a menos que usted le pida explícitamente que no lo haga estableciendo 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ás viendo.

Pruébalo.

xcud avatar Feb 19 '2009 19:02 xcud

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ıç avatar Sep 09 '2011 07:09 Engin Ardıç

Esta misma situación y error también pueden surgir con un proxy de servicio web SOAP generado por un asistente predeterminado (no al 100% si este también es el caso en la System.ServiceModelpila WCF) 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 entiende (comúnmente un Expectencabezado como parte de un HTTP POSTo PUTuna solicitud debido a una convención de protocolo estándar de enviar la solicitud en dos partes, como se explica en los Comentarios aquí )

... dando un 417.

Como se explica en las otras respuestas, si el problema específico que encuentra es que el Expectencabezado está causando el problema, entonces ese problema específico se puede solucionar realizando una desactivació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: es posible que la pila aún esté usando elementos específicos 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 generado automáticamente supone que está bien utilizar a ciegas las funciones HTTP 1.1, ya que todo el mundo lo entiende. Para detener esta suposición para un proxy de servicio web específico, se puede cambiar la anulación del valor predeterminado subyacente HttpWebRequest.ProtocolVersionde 1.1 creando una clase de Proxy derivada que 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 le escupió el asistente Agregar referencia web?)


ACTUALIZACIÓN: Aquí hay una 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 avatar Jun 06 '2012 14:06 Ruben Bartelink