HTTP POST возвращает ошибку: 417 "Ожидание не выполнено".

Когда я пытаюсь отправить POST на URL-адрес, это приводит к следующему исключению:

Удаленный сервер возвратил ошибку: (417) Ожидание не выполнено.

Вот пример кода:

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.

Использование пары HttpWebRequest/HttpWebResponse или HttpClient не имеет значения.

Что вызывает это исключение?

Ответ 1

System.Net.HttpWebRequest добавляет заголовок "HTTP-заголовок" "Ожидание: 100-Продолжить" для каждого запроса, если вы явно не попросите его не устанавливать, this static property до false:

System.Net.ServicePointManager.Expect100Continue = false;

Некоторые серверы дросселируют этот заголовок и отправляют обратно 417 ошибку, которую вы видите.

Сделайте снимок.

Ответ 2

Другой способ -

Добавьте эти строки в раздел конфигурации файла конфигурации приложения:

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

Ответ 3

Такая же ситуация и ошибка могут возникать и с созданным по умолчанию мастером профайла SOAP Web Service (не 100%, если это так происходит в стеке WCF System.ServiceModel), когда во время выполнения:

  • машина конечного пользователя настроена (в настройках Интернета) для использования прокси-сервера, который не понимает HTTP 1.1
  • клиент отправляет то, что прокси-сервер HTTP 1.0 не понимает (обычно заголовок Expect как часть запроса HTTP POST или PUT из-за стандартного соглашения о протоколе отправки запроса в две части как описано в примечаниях здесь)

..., давая 417.

Как описано в других ответах, если конкретная проблема, с которой вы столкнулись, состоит в том, что заголовок Expect вызывает проблему, тогда эту конкретную проблему можно перенаправить, выполняя относительно глобальное отключение двухсекционного PUT/POST через System.Net.ServicePointManager.Expect100Continue.

Однако это не устраняет полную основную проблему - стек может по-прежнему использовать определенные HTTP 1.1 такие вещи, как KeepAlives и т.д. (хотя во многих случаях другие ответы охватывают основные случаи.)

Фактическая проблема заключается в том, что автогенерированный код предполагает, что он в порядке, чтобы идти слепо, используя объекты HTTP 1.1, как это все понимают. Чтобы остановить это предположение для определенного прокси-сервера веб-службы, можно изменить переопределяющее значение по умолчанию HttpWebRequest.ProtocolVersion по умолчанию 1.1, создав производный класс Proxy, который переопределяет 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;
    }
}

(где MyWS является прокси-сервером, который добавляет мастер добавления веб-ссылок на вас.)


UPDATE: Здесь я использую in production:

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

Ответ 4

Использует ли форма, которую вы пытаетесь эмулировать, иметь два поля, имя пользователя и пароль?

Если это так, эта строка:

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

неверно.

вам понадобится две строки, например:

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

Edit:

Хорошо, так как это не проблема, один из способов решения этой проблемы - использовать что-то вроде Fiddler или Wireshark, чтобы смотреть, что отправляется на веб-сервер из браузера, и сравнить его с тем, что отправляется с вашего код. Если вы перейдете на обычный порт 80 из .Net, Fiddler все равно захватит этот трафик.

Возможно, есть какое-то другое скрытое поле в форме, которую веб-сервер ожидает, что вы не отправляете.

Ответ 5

Решение со стороны прокси-сервера, я столкнулся с некоторыми проблемами в процессе установления SSL-связи, и мне пришлось заставить свой прокси-сервер отправлять запросы с использованием HTTP/1.0 для решения проблемы, установив этот аргумент в httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1 после этого я столкнулся с ошибкой 417, поскольку приложение-клиент использовал HTTP/1.1, а прокси-сервер был вынужден использовать HTTP/1.0, проблема была решена путем установки этого параметра в httpd.conf на стороне прокси-сервера RequestHeader unset Expect early без необходимости менять что-либо на стороне клиента, надеюсь, что это поможет.

Ответ 6

Для Powershell это

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

Ответ 7

Если вы используете " HttpClient", и вы не хотите использовать глобальную конфигурацию, чтобы повлиять на все ваши программы, которые вы можете использовать:

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

Я использую " WebClient". Я думаю, вы можете попытаться удалить этот заголовок, вызвав:

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

Ответ 8

В моей ситуации эта ошибка возникает, только если мой клиентский компьютер имеет строгую политику брандмауэра, что не позволяет моей программе общаться с веб-службой.

Таким образом, единственное решение, которое я смог найти, - это уловить ошибку и сообщить пользователю об изменении настроек брандмауэра вручную.

Ответ 9

Подход web.config работает для сервисов форм InfoPath, вызываемых правилами включения веб-службы IntApp.

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