HTTP POST devuelve error: 417 “Expectation Failed”.

Cuando bash enviar POST a una URL, se produce la siguiente excepción:

El servidor remoto devolvió un error: (417) Expectation Failed.

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 par HttpWebRequest/HttpWebResponse o un HttpClient no hace la diferencia.

¿Qué está causando esta excepción?

System.Net.HttpWebRequest agrega el encabezado ‘encabezado HTTP’. Espera: 100-Continuar ” para cada solicitud a menos que explícitamente se lo solicite estableciendo esta propiedad estática en falso:

 System.Net.ServicePointManager.Expect100Continue = false; 

Algunos servidores se ahogan en ese encabezado y envían el error 417 que estás viendo.

Dale una oportunidad.

De otra manera –

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

      

Esta misma situación y error también pueden surgir con un proxy del Servicio web SOAP generado por el asistente predeterminado (no es 100% si este es también el caso en la stack WCF System.ServiceModel ) 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 encabezado de Expect como parte de una POST HTTP POST o PUT debido a una convención de protocolo estándar de enviar la solicitud en dos partes como se describe en las Observaciones aquí )

… produciendo un 417.

Como se cubre en las otras respuestas, si el problema específico con el 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 la transmisión PUT / POST de dos partes a través del System.Net.ServicePointManager.Expect100Continue .

Sin embargo, esto no soluciona el problema subyacente completo: es posible que la stack siga utilizando elementos específicos de HTTP 1.1, como KeepAlives, etc. (aunque en muchos casos las otras respuestas sí 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 para un proxy de servicio web específico, se puede cambiar la anulación de la HttpWebRequest.ProtocolVersion subyacente predeterminada del valor predeterminado de 1.1 mediante la creación de una clase Proxy derivada que anula la sustitución protected override WebRequest GetWebRequest(Uri uri) como se muestra en esta publicación :

 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 que el asistente Agregar referencia web le escupió).


ACTUALIZACIÓN: Aquí hay una IML 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 }; } } 

¿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 con éxito lo que se envía al servidor web desde el navegador, luego compararlo con lo que se envía desde el 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.

Solución del lado del servidor proxy, tuve algunos problemas en el proceso de enlace SSL y tuve que forzar a mi servidor proxy a enviar solicitudes usando HTTP / 1.0 para resolver el problema estableciendo este argumento en 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 usaba HTTP / 1.1 y el proxy se vio forzado a usar HTTP / 1.0, el problema fue resuelto estableciendo este parámetro en httpd.conf en el lado del proxy RequestHeader unset Expect early sin la necesidad de cambiar nada en el lado del cliente, espero que esto ayude.

Si está utilizando ” HttpClient ” y no desea utilizar la configuración global para afectar todo lo que progtwig, puede usar:

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

Si está utilizando ” WebClient “, creo que puede intentar eliminar este encabezado llamando:

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

Para Powershell es

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

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

         

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 progtwig se comunique con el servicio web.

Entonces, 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.