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 не имеет значения.

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

11 ответов

Решение

System.Net.HttpWebRequest добавляет заголовок "HTTP-заголовок"Expect: 100-Continue"" к каждому запросу, если вы явно не попросите его об этом, установив для этого статического свойства значение false:

System.Net.ServicePointManager.Expect100Continue = false;

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

Дайте этому шанс.

По-другому -

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

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

Та же самая ситуация и ошибка могут также возникнуть с мастером по умолчанию, сгенерированным прокси-сервером веб-службы SOAP (не 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 прокси-сервер, на который выпал мастер добавления веб-ссылок.)


ОБНОВЛЕНИЕ: Вот что я использую в производстве:

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

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

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

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

не является правильным.

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

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

Редактировать:

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

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

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

Для Powershell это

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

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

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

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

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

Убедитесь, что ваше сетевое соединение не перенаправляет.

У меня была эта проблема, когда я использовал неправильный Wi-Fi, и любой веб-запрос перенаправлялся на корпоративную страницу входа.

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

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

Это может быть вызвано отсутствием правильной авторизации при обращении к конечной точке/контроллеру. Если ваш контроллер украшен значкомAuthorizeAttributeи ваш запрос не соответствует этому разрешению, вы получите

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

  <system.net>
    <defaultProxy />
    <settings> <!-- 20130323 bchauvin -->
        <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>
Другие вопросы по тегам