HTTP POST Retorna Erro: 417 “Expectativa Falhou”.

Quando tento POSTAR para um URL, resulta na seguinte exceção:

O servidor remoto retornou um erro: (417) Expectation Failed.

Aqui está um código de exemplo:

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 um par HttpWebRequest/HttpWebResponse ou um HttpClient não faz diferença.

O que está causando essa exceção?

System.Net.HttpWebRequest adiciona o header ‘Cabeçalho HTTP “Expect: 100-Continue”‘ para cada solicitação, a menos que você peça explicitamente que não, definindo esta propriedade estática como false:

 System.Net.ServicePointManager.Expect100Continue = false; 

Alguns servidores engasgam com esse header e mandam de volta o erro 417 que você está vendo.

Dê uma chance.

Outro caminho –

Adicione estas linhas à seção de configuração do arquivo de configuração do seu aplicativo:

      

Essa mesma situação e erro também podem surgir com um proxy padrão do Serviço Web Proxy gerado pelo assistente (não 100%, se esse também for o caso na pilha WCF System.ServiceModel ), quando no tempo de execução:

  • a máquina do usuário final está configurada (nas configurações da Internet) para usar um proxy que não entende o HTTP 1.1
  • o cliente acaba enviando algo que um proxy HTTP 1.0 não entende (geralmente um header Expect como parte de uma solicitação HTTP POST ou PUT devido a uma convenção de protocolo padrão de enviar a solicitação em duas partes, conforme abordado nas Observações aqui )

… gerando um 417.

Como abordado nas outras respostas, se o problema específico que você encontrar é que o header Expect está causando o problema, esse problema específico pode ser roteado fazendo um desligamento relativamente global da transmissão PUT / POST de duas partes via System.Net.ServicePointManager.Expect100Continue .

No entanto, isso não corrige o problema subjacente completo – a pilha ainda pode estar usando coisas específicas do HTTP 1.1, como KeepAlives etc. (embora em muitos casos as outras respostas cubram os casos principais).

O problema real é, no entanto, que o código gerado automaticamente pressupõe que não há problema em usar cegamente as facilidades HTTP 1.1, pois todos entendem isso. Para parar essa suposição para um proxy específico do Serviço da Web, é possível replace o HttpWebRequest.ProtocolVersion subjacente padrão do padrão de 1.1 , criando uma class Proxy derivada que substitui a substituição protected override WebRequest GetWebRequest(Uri uri) conforme mostrado neste post : –

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

(onde o MyWS é o proxy que o assistente Add Web Reference cuspiu para você.)


UPDATE: Aqui está um impl estou usando na produção:

 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 }; } } 

O formulário que você está tentando emular tem dois campos, nome de usuário e senha?

Se sim, esta linha:

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

não está correto.

você precisaria de duas linhas como:

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

Editar:

Certo, como esse não é o problema, uma maneira de resolver isso é usar algo como Fiddler ou Wireshark para observar com êxito o que está sendo enviado ao servidor da Web a partir do navegador e compará-lo ao que está sendo enviado pelo seu código. Se você estiver indo para uma porta 80 normal do .Net, o Fiddler ainda capturará esse tráfego.

Provavelmente, há algum outro campo oculto no formulário que o servidor da Web espera que você não esteja enviando.

Solução do lado do proxy, enfrentei alguns problemas no processo de handshake SSL e tive que forçar meu servidor proxy a enviar solicitações usando HTTP / 1.0 para resolver o problema definindo esse argumento no httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1 depois que eu enfrentei o erro 417 como meu aplicativo de clientes estava usando HTTP / 1.1 e o proxy foi forçado a usar HTTP / 1.0, o problema foi resolvido configurando este parâmetro no httpd.conf no lado do proxy RequestHeader unset Expect early sem a necessidade de alterar nada no lado do cliente, espero que isso ajude.

Se você estiver usando ” HttpClient ” e não quiser usar a configuração global para afetar todos os programas, use:

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

Eu estou usando ” WebClient ” Eu acho que você pode tentar remover este header chamando:

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

Para Powershell é

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

A abordagem web.config funciona para chamadas de serviços de formulário do InfoPath para regras habilitadas para serviços da Web do IntApp.

         

Na minha situação, esse erro parece ocorrer apenas se o computador do meu cliente tiver uma diretiva de firewall rígida, o que impede que meu programa se comunique com o serviço da web.

Então, a única solução que consegui encontrar é pegar o erro e informar ao usuário sobre como alterar as configurações do firewall manualmente.