HTTP POST возвращает ошибку: 417 «Ожидание не выполнено». - PullRequest
208 голосов
/ 19 февраля 2009

Когда я пытаюсь отправить 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 не имеет значения.

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

Ответы [ 9 ]

467 голосов
/ 19 февраля 2009

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

System.Net.ServicePointManager.Expect100Continue = false;

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

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

113 голосов
/ 09 сентября 2011

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

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

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>
30 голосов
/ 06 июня 2012

Такая же ситуация и ошибка могут возникать и при использовании прокси-сервера 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 , создав производный прокси-класс, который переопределяет 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 };
    }
}
5 голосов
/ 19 февраля 2009

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

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

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

неверно.

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

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

Edit:

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

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

3 голосов
/ 28 мая 2013

Решение со стороны прокси, я столкнулся с некоторыми проблемами в процессе рукопожатия 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 без необходимости что-либо менять на стороне клиента, надеюсь, это поможет.

2 голосов
/ 01 марта 2018

Для Powershell это

[System.Net.ServicePointManager]::Expect100Continue = $false
1 голос
/ 11 июля 2017

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

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

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

 var client = new WebClient();
 client.Headers.Remove(HttpRequestHeader.Expect);
0 голосов
/ 21 июля 2015

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

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

0 голосов
/ 25 марта 2013

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

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