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

когда я пытаюсь опубликовать 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 ответов


Система.Сеть.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 stack) во время выполнения:

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


UPDATE: вот impl, который я использую в производстве:

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");

Edit:

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

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


решение со стороны прокси, я столкнулся с некоторыми проблемами в процессе рукопожатия 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 на сервере proxy RequestHeader unset Expect early не нужно ничего менять в клиентская сторона, надеюсь, это поможет.


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

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

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

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

для Powershell это

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

веб.подход config работает для вызовов InfoPath form services правилам с поддержкой веб-службы IntApp.

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

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

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