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
заголовок как часть HTTPPOST
или же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 1
SetEnv 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>