HTTP POST Returns Error: 417 "Ekspektasi Gagal."

212

Ketika saya mencoba POST ke URL, hasilnya adalah pengecualian berikut:

Server jauh mengembalikan kesalahan: (417) Ekspektasi Gagal.

Berikut ini contoh kode:

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.

Menggunakan HttpWebRequest/HttpWebResponsepasangan atau HttpClienttidak tidak ada bedanya.

Apa yang menyebabkan pengecualian ini?

Saeb Amini
sumber
2
Masalah ini tampaknya terjadi ketika aplikasi Anda berkomunikasi melalui server proxy. Aplikasi .NET yang saya tulis berfungsi saat terhubung langsung ke internet tetapi tidak ketika berada di belakang server proxy.
Salman A
2
Mengamati kondisi ini ketika klien menjalankan melalui server proxy HTTP 1.0 (hanya). Klien (proxy asmx tanpa konfigurasi apa pun) mengirimkan permintaan HTTP 1.1 dan proxy (sebelum server mana pun bisa terlibat) kemudian menolak apa yang dikirim oleh proxy tersebut. Jika pengguna akhir memiliki masalah ini, menggunakan solusi konfigurasi di bawah ini adalah solusi yang tepat karena akan menyebabkan permintaan dihasilkan tanpa bergantung pada proksi yang memahami Expectheader yang secara default ditambahkan seperti halnya Expect100Continuesecara truedefault.
Ruben Bartelink

Jawaban:

478

System.Net.HttpWebRequest menambahkan header 'HTTP header "Expect: 100-Continue"' untuk setiap permintaan kecuali Anda secara eksplisit memintanya untuk tidak mengatur properti statis ini menjadi false:

System.Net.ServicePointManager.Expect100Continue = false;

Beberapa server tersedak pada header itu dan mengirim kembali 417 kesalahan yang Anda lihat.

Cobalah.

xcud
sumber
5
Saya memiliki beberapa kode yang berbicara dengan Twitter yang tiba-tiba berhenti bekerja sehari setelah Natal. Mereka telah melakukan upgrade atau perubahan konfigurasi yang menyebabkan server mereka mulai tersedak header itu. Sulit menemukan perbaikannya.
xcud
8
Saya pikir saya mengambil 10 poin tambahan untuk mendapatkan jawaban yang diterima di utas yang diposting oleh Jon Skeet.
xcud
1
Terima kasih! Ini harus dicatat di suatu tempat dalam contoh msdn
Eugene
25
Anda juga dapat menentukan properti itu di app.config: <system.net> <settings> <servicePointManager expect100Continue = "false" />. nahidulkibria.blogspot.com/2009/06/...
Andre Luus
2
Catatan: pengaturan ini juga berlaku untuk Referensi Layanan dan saya menganggap Referensi Web.
Myster
114

Cara lain -

Tambahkan baris ini ke bagian konfigurasi file konfigurasi aplikasi Anda:

<system.net>
    <settings>
        <servicePointManager expect100Continue="false" />
    </settings>
</system.net>
Engin Ardıç
sumber
6
Bekerja sangat baik ketika Anda harus melakukan perubahan operasional dan tidak siap untuk perubahan kode.
dawebber
1
Apa yang dilakukan garis konfigurasi itu?
J86
31

Situasi dan kesalahan yang sama ini juga dapat muncul dengan wizard default yang dihasilkan proksi SOAP Web Service (tidak 100% jika ini juga terjadi pada System.ServiceModeltumpukan WCF ) ketika saat runtime:

  • mesin pengguna akhir dikonfigurasikan (dalam Pengaturan Internet) untuk menggunakan proxy yang tidak mengerti HTTP 1.1
  • klien akhirnya mengirim sesuatu yang tidak dimengerti oleh proxy HTTP 1.0 (umumnya Expectheader sebagai bagian dari HTTP POSTatau PUTpermintaan karena konvensi protokol standar untuk mengirim permintaan dalam dua bagian sebagaimana dibahas dalam Catatan di sini )

... menghasilkan 417.

Seperti yang tercakup dalam jawaban lain, jika masalah spesifik yang Anda temui adalah bahwa Expectheader menyebabkan masalah, maka masalah spesifik tersebut dapat dialihkan dengan melakukan pematian global relatif dari transmisi PUT / POST dua bagian via System.Net.ServicePointManager.Expect100Continue.

Namun ini tidak memperbaiki masalah mendasar yang mendasari - tumpukan mungkin masih menggunakan HTTP 1.1 hal-hal spesifik seperti KeepAlives dll. (Meskipun dalam banyak kasus jawaban lain mencakup kasus-kasus utama.)

Namun masalah sebenarnya adalah bahwa kode yang dibuat secara otomatis mengasumsikan bahwa tidak apa-apa untuk pergi secara buta menggunakan fasilitas HTTP 1.1 karena semua orang memahami hal ini. Untuk menghentikan asumsi ini untuk proksi Layanan Web tertentu, seseorang dapat mengubah mengabaikan default yang mendasari HttpWebRequest.ProtocolVersiondari default 1.1 dengan membuat kelas Proxy turunan yang menimpa seperti yang ditunjukkan dalam posting ini : -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;
    }
}

(di mana MyWSproksi yang ditambahkan oleh wizard Referensi Web pada Anda.)


UPDATE: Ini alat yang saya gunakan dalam produksi:

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 };
    }
}
Ruben Bartelink
sumber
2
Saya tahu Anda memposting ini beberapa waktu yang lalu, tetapi Ruben, Anda seorang penyelamat. Masalah ini telah membuat saya gila sampai saya menemukan solusi Anda dan itu bekerja dengan sempurna. Bersulang!
Christopher McAtackney
1
@ChrisMcAtackney Sama-sama. Jelas tampak sepadan dengan usaha mendokumentasikannya pada waktu itu ... masalah umum yang ada di sekitar menjadi isu prioritas utama dan hanya mengganggu saya sampai saya menyelidikinya dengan benar - namun tampaknya tidak ada jus Google untuk sisi masalah itu. dan itu adalah salah satu pos Attwood chap dari jauh yang mendorong saya untuk melakukannya. (Suara positif dengan komentar seperti ini BTW fantastis)
Ruben Bartelink
1
Tambahan dan contoh yang bagus. Terima kasih!
Fadi Chamieh
5

Apakah formulir yang Anda coba tiru memiliki dua bidang, nama pengguna dan kata sandi?

Jika demikian, baris ini:

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

tidak benar.

Anda memerlukan dua baris seperti:

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

Edit:

Oke, karena itu bukan masalahnya, salah satu cara untuk mengatasi ini adalah dengan menggunakan sesuatu seperti Fiddler atau Wireshark untuk menonton apa yang sedang dikirim ke server web dari browser dengan sukses, kemudian membandingkannya dengan apa yang dikirim dari kode Anda. Jika Anda pergi ke port normal 80 dari .Net, Fiddler masih akan menangkap lalu lintas ini.

Mungkin ada beberapa bidang tersembunyi lainnya pada formulir yang server web harapkan tidak Anda kirim.

Moose
sumber
3

Solusi dari sisi proxy, saya menghadapi beberapa masalah dalam proses handshake SSL dan saya harus memaksa server proxy saya untuk mengirim permintaan menggunakan HTTP / 1.0 untuk menyelesaikan masalah dengan menetapkan argumen ini di httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1setelah itu saya menghadapi kesalahan 417 sebagai aplikasi klien saya menggunakan HTTP / 1.1 dan proxy terpaksa menggunakan HTTP / 1.0, masalahnya diselesaikan dengan mengatur parameter ini di httpd.conf di sisi proxy RequestHeader unset Expect earlytanpa perlu mengubah apa pun di sisi klien, semoga ini membantu .

Hytham
sumber
2

Untuk Powershell itu

[System.Net.ServicePointManager]::Expect100Continue = $false
TNT
sumber
1

Jika Anda menggunakan " HttpClient ", dan Anda tidak ingin menggunakan konfigurasi global untuk memengaruhi semua program yang bisa Anda gunakan:

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

Saya Anda menggunakan " WebClient " Saya pikir Anda dapat mencoba menghapus tajuk ini dengan menelepon:

 var client = new WebClient();
 client.Headers.Remove(HttpRequestHeader.Expect);
Aviram Fireberger
sumber
0

Dalam situasi saya, kesalahan ini tampaknya hanya terjadi jika komputer klien saya memiliki kebijakan firewall yang ketat, yang mencegah program saya untuk berkomunikasi dengan layanan web.

Jadi satu-satunya solusi yang bisa saya temukan adalah menangkap kesalahan dan memberi tahu pengguna tentang mengubah pengaturan firewall secara manual.

Emre Can Serteli
sumber
-1

Pendekatan web.config berfungsi untuk panggilan layanan formulir InfoPath ke aturan yang diaktifkan layanan web IntApp.

  <system.net>
    <defaultProxy />
    <settings> <!-- 20130323 bchauvin -->
        <servicePointManager expect100Continue="false" />
    </settings>
  </system.net>
BobC
sumber
2
dup of stackoverflow.com/a/7358457/11635 Silakan berkomentar di sana jika Anda ingin menambahkan poin
Ruben Bartelink