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
заголовок как часть HTTPPOST
или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);
веб.подход config работает для вызовов InfoPath form services правилам с поддержкой веб-службы IntApp.
<system.net>
<defaultProxy />
<settings> <!-- 20130323 bchauvin -->
<servicePointManager expect100Continue="false" />
</settings>
</system.net>
в моей ситуации эта ошибка возникает только в том случае, если компьютер моего клиента имеет строгую политику брандмауэра, которая запрещает моей программе общаться с веб-службой.
поэтому единственное решение, которое я мог найти, - это поймать ошибку и сообщить пользователю об изменении настроек брандмауэра вручную.