HTTP POST Повернення Помилка: 417 "Очікування не вдалося."


212

Коли я намагаюсь 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не має значення.

Що викликає цей виняток?


2
Здається, проблема виникає, коли ваша програма спілкується через проксі-сервер. Програма, яку я написав .NET, працювала, коли вона була безпосередньо підключена до Інтернету, але не тоді, коли вона стояла за проксі-сервером.
Салман

2
Ця умова дотримується, коли клієнт працює через проксі-сервер HTTP 1.0 (тільки). Клієнт (asmx proxy без будь-якої конфігурації) надсилає запит HTTP 1.1, а проксі (раніше, ніж будь-який сервер коли-небудь зможе залучитись) потім відхиляє те, що проксі надсилає. Якщо кінцевий користувач має цю проблему, використовуючи рішення конфігурації нижче є підходящим обхідним шляхом , оскільки це може викликати запити до генеруватися без опори на проксі розуміє Expectзаголовок , який за замовчуванням додається в Expect100Continueце trueза замовчуванням.
Рубен Бартелінк

Відповіді:


478

System.Net.HttpWebRequest додає заголовок "HTTP-заголовок" Очікуйте: 100-Продовжуйте "'до кожного запиту, якщо ви прямо не попросите цього не встановлювати це статичне властивість на значення false:

System.Net.ServicePointManager.Expect100Continue = false;

Деякі сервери задушуються над цим заголовком і надсилають назад помилку 417, яку ви бачите.

Дайте, що постріл.


5
У мене був якийсь код, який розмовляв у Twitter, який раптом перестав працювати наступного дня після Різдва. Вони здійснили оновлення або зміну конфігурації, через що їх сервери почали задихатися в цьому заголовку. Болі було знайти виправлення.
xcud

8
Я думаю, що я набрав додаткові 10 балів за отримання відповіді, прийнятої в темі, в яку Джон Скіт розмістив рішення.
xcud

1
Дякую! Це слід зазначити десь у прикладах msdn,
Євген

25
Ви також можете вказати цю властивість у своїй програмі app.config: <system.net> <settings> <servicePointManager oce100Continue = "false" />. nahidulkibria.blogspot.com/2009/06/…
Андре Луус

2
Примітка: це налаштування також стосується ServiceReferences, і я припускаю, що WebReferences.
Містер

114

Інший спосіб -

Додайте ці рядки до розділу конфігурації файлу конфігурації програми:

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

6
Працює дуже добре, коли вам доведеться внести оперативні зміни і не готові до зміни коду.
dawebber

1
Що робить цей рядок конфігурації?
J86

31

Ця ж ситуація та помилка також можуть виникнути, коли майстер за промовчанням створив проксі-сервер веб-сервісу SOAP (не 100%, якщо це також має місце на System.ServiceModelстеку WCF ) під час виконання:

  • машина кінцевого користувача налаштована (у налаштуваннях Інтернету) для використання проксі-сервера, який не розуміє 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 };
    }
}

2
Я знаю, що ви це розмістили досить давно, але Рубен, ви рятувальник життя. Це питання зводило мене з розуму, поки я не натрапив на ваше рішення, і воно прекрасно працює. Ура!
Крістофер МакАктні

1
@ChrisMcAtackney Ласкаво просимо. Це, безумовно, здавалося, варто намагатися документувати його в їх час ... загальна проблема постала навколо меж, щоб стати проблемою першочергового значення, і просто турбувала мене, поки я не дослідив це належним чином - все ж, здається, не було жодного соку Google для та сторона питання. і це було одне із тих постів, які пройшли в Аттвуді, з боку назад, що підштовхувало мене до цього. (Оголошення з таким коментарем є фантастичним BTW)
Ruben Bartelink

1
Чудове доповнення та приклади. Дякую!
Fadi Chamieh

5

У формі, яку ви намагаєтеся наслідувати, є два поля, ім’я користувача та пароль?

Якщо так, цей рядок:

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

невірно.

вам знадобиться два рядки на кшталт:

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

Редагувати:

Гаразд, оскільки це не проблема, один із способів вирішити це - використовувати щось на кшталт Fiddler або Wireshark для успішного перегляду того, що надсилається на веб-сервер із браузера, а потім порівняти це з тим, що надсилається з вашого коду. Якщо ви збираєтесь до звичайного порту 80 від .Net, Fiddler все одно захопить цей трафік.

Напевно, є якесь інше приховане поле у ​​формі, яку веб-сервер очікує, що ви його не надсилаєте.


3

Рішення з боку проксі, я зіткнувся з деякими проблемами в процесі рукостискання 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

Для Powershell це так

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

1

Якщо ви використовуєте " HttpClient ", і ви не хочете, щоб глобальна конфігурація впливала на все, що ви можете використовувати:

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

Я використовую " WebClient ". Я думаю, ви можете спробувати видалити цей заголовок, зателефонувавши:

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

0

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

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


-1

Підхід web.config працює для викликів служб форми InfoPath до правил увімкненого веб-сервісу IntApp.

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

2
dup of stackoverflow.com/a/7358457/11635 Будь ласка, прокоментуйте там, якщо хочете додати крапку
Ruben Bartelink
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.