2009-02-19 16 views
193

Cuando intenta registrar a una dirección URL que da lugar a la siguiente excepción:HTTP POST devuelve error: 417 "Expectation Failed."

The remote server returned an error: (417) Expectation Failed.

Aquí está un ejemplo de código:

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. 

El uso de un par HttpWebRequest/HttpWebResponse o un HttpClient no hace una diferencia.

¿Qué está causando esta excepción?

+2

El problema parece ocurrir cuando su aplicación se comunica a través de un servidor proxy. Una aplicación .NET que escribí funcionó cuando estaba conectada directamente a Internet, pero no cuando estaba detrás de un servidor proxy. –

+2

Se observó esta condición cuando un cliente se está ejecutando a través de un servidor proxy HTTP 1.0 (solamente).El cliente (proxy asmx sin ninguna configuración) está enviando una solicitud HTTP 1.1 y el proxy (antes de que cualquier servidor pueda participar) y luego rechaza lo que envía el proxy. Si un usuario final tiene este problema, usar la [solución de configuración a continuación] (http://stackoverflow.com/a/7358457/11635) es una solución apropiada ya que provocaría que se generaran solicitudes sin confiar en la comprensión del proxy. el encabezado 'Expect' que de forma predeterminada se agrega como' Expect100Continue' es 'true' de manera predeterminada. –

Respuesta

445

System.NET.HttpWebRequest añade la cabecera 'cabecera HTTP 'Hay que esperar: 100-continuar'' a cada solicitud a menos que pedir explícitamente que no utilizará estableciendo this static property false:

Algunos servidores ahogan en ese encabezado y envíe de vuelta el error 417 que está viendo.

Dale una oportunidad.

+68

wow, +1 por muy oscuro! – Moose

+5

Tenía un código que hablaba con Twitter que de repente dejó de funcionar el día después de Navidad. Hicieron una actualización o un cambio de configuración que hizo que sus servidores comenzaran a asfixiarse en ese encabezado. Fue un dolor encontrar la solución. – xcud

+7

Creo que recogí 10 puntos adicionales por aceptar una respuesta en un hilo en el que Jon Skeet publicó una solución. – xcud

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.

se necesitaría dos líneas como:

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

Editar:

bien, ya que no es el problema, una forma de hacer frente a esto es usar algo como violinista o Wireshark para ver lo que es ser enviado 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 normal 80 desde .Net, Fiddler seguirá capturando este tráfico.

Probablemente haya algún otro campo oculto en el formulario que el servidor web espera que no esté enviando.

109

Otra forma -

Añadir estas líneas a la sección de configuración del archivo de configuración de la aplicación:

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

Funciona muy bien cuando tiene que hacer un cambio operacional y no está listo para un cambio de código. – dawebber

+0

¿Qué hace esa línea de configuración? – Ciwan

30

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

  • el usuario final máquina 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 encabezado Expect como parte de una solicitud HTTP POST o PUT debido a una convención de protocolo estándar de enviar la solicitud en dos partes as covered in the Remarks here)

... obteniendo un 417.

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

Sin embargo, esto no se resuelve el problema de fondo completa - la pila pueda estar utilizando HTTP 1.1 cosas específicas, tales como KeepAlive etc. (aunque en muchos casos las otras respuestas cubren los casos principales.)

Sin embargo, el problema real es que el código autogenerado asume que está bien pasar ciegamente a través de las instalaciones de HTTP 1.1 ya que todos entienden esto. Para detener esta suposición de un proxy de servicio web específica, se puede cambiar reemplazar el valor predeterminado subyacente HttpWebRequest.ProtocolVersion del valor predeterminado de 1.1 mediante la creación de una clase de proxy derivada que anula protected override WebRequest GetWebRequest(Uri uri)as shown in this post: -

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

(donde MyWS es el proxy de la asistente para agregar referencia web escupió a la vista)


ACTUALIZACIÓN:. he aquí un impl estoy usando en la 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 }; 
    } 
} 
+2

Sé que publicaste esto hace bastante tiempo, pero Rubén, eres un salvavidas. Este problema me está volviendo loco hasta que encontré su solución y funciona perfectamente. ¡Aclamaciones! –

+1

@ChrisMcAtackney De nada. Definitivamente valió la pena el esfuerzo de documentarlo en su momento ... el problema general estaba a punto de convertirse en un asunto de máxima prioridad y me molestó hasta que lo investigué adecuadamente, sin embargo, no parecía haber ningún jugo de google para ese lado del problema. y fue uno de los mensajes de ese muchacho de Attwood que me empujaron a hacerlo. (Un voto positivo con un comentario como este es fantástico por cierto) –

+1

Maravillosa adición y ejemplos. ¡Gracias! –

0

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

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

dup de http://stackoverflow.com/a/7358457/11635 Comente allí si desea agregar un punto –

3

Solución de un lado proxy, que se enfrentan algunos problemas en el proceso de establecimiento de conexión SSL y tuve que forzar mi servidor proxy para enviar solicitudes a través de HTTP/1.0 para resolver el problema mediante el establecimiento de este argumento en el httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1 Después de eso me enfrenté al error 417 ya que la aplicación de mis clientes estaba usando HTTP/1.1 y el proxy se vio forzado a usar HTTP/1.0, el problema se resolvió estableciendo este parámetro en el httpd.conf en el lado del proxy RequestHeader unset Expect early sin la necesidad para cambiar cualquier cosa en el lado del cliente, espero que esto ayude.

0

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

Así que la única solución que pude encontrar es detectar el error e informar al usuario sobre el cambio manual de la configuración del firewall.

1

Si está utilizando "HttpClient", y que no quieren usar configuración global que afecta todo lo que programa que puede utilizar:

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

que está utilizando "WebClient" Yo creo que se pueda tratar de eliminar esta cabecera llamando:

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

para Powershell es

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