Lỗi trả về POST POST: Không thể mong đợi


212

Khi tôi cố gắng POST lên một URL, nó sẽ dẫn đến ngoại lệ sau:

Máy chủ từ xa đã trả về lỗi: (417) Không thể mong đợi.

Đây là một mã mẫu:

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.

Sử dụng một HttpWebRequest/HttpWebResponsecặp hoặc HttpClientkhông làm nên sự khác biệt.

Điều gì gây ra ngoại lệ này?


2
Vấn đề dường như xảy ra khi ứng dụng của bạn liên lạc qua máy chủ proxy. Một ứng dụng .NET tôi đã viết hoạt động khi nó được kết nối trực tiếp với internet nhưng không phải khi nó ở phía sau máy chủ proxy.
Salman A

2
Đã quan sát tình trạng này khi máy khách đang chạy qua máy chủ proxy HTTP 1.0 (chỉ). Máy khách (proxy asmx không có bất kỳ cấu hình nào) đang gửi yêu cầu HTTP 1.1 và proxy (trước khi bất kỳ máy chủ nào có thể tham gia) sau đó từ chối những gì proxy gửi vào. Nên một người dùng cuối có vấn đề này, bằng cách sử dụng giải pháp cấu hình dưới đây là một cách giải quyết thích hợp vì nó sẽ gây ra các yêu cầu để được tạo ra mà không có một sự phụ thuộc vào proxy hiểu Expecttiêu đề mà theo mặc định được thêm vào như Expect100Continuetruetheo mặc định.
Ruben Bartelink

Câu trả lời:


478

System.Net.HttpWebRequest thêm tiêu đề 'Tiêu đề HTTP "Mong đợi: 100-Tiếp tục"' cho mọi yêu cầu trừ khi bạn yêu cầu rõ ràng là không bằng cách đặt thuộc tính tĩnh này thành false:

System.Net.ServicePointManager.Expect100Continue = false;

Một số máy chủ bị sặc trên tiêu đề đó và gửi lại lỗi 417 bạn đang thấy.

Cho nó một phát súng.


5
Tôi đã có một số mã nói chuyện với Twitter đột nhiên ngừng hoạt động vào ngày sau Giáng sinh. Họ đã thực hiện nâng cấp hoặc thay đổi cấu hình khiến máy chủ của họ bắt đầu nghẹt thở trên tiêu đề đó. Đó là một nỗi đau để tìm các sửa chữa.
xcud

8
Tôi nghĩ rằng tôi đã chọn thêm 10 điểm để nhận được câu trả lời được chấp nhận trong một chủ đề mà Jon Skeet đã đăng một giải pháp vào.
xcud

1
Cảm ơn! Điều này cần được lưu ý ở đâu đó trong các ví dụ msd
Eugene

25
Bạn cũng có thể chỉ định thuộc tính đó trong ứng dụng của mình.config: <system.net> <settings> <servicePointManager wish100Continue = "false" />. nahidulkibria.blogspot.com/2009/06/ khăn
Andre Luus

2
Lưu ý: cài đặt này cũng áp dụng cho ServiceReferences và tôi giả sử WebReferences.
Bí ẩn

114

Cách khác -

Thêm các dòng này vào phần cấu hình tệp cấu hình ứng dụng của bạn:

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

6
Hoạt động rất tốt khi bạn phải thực hiện thay đổi vận hành và chưa sẵn sàng cho việc thay đổi mã.
dawebber

1
Dòng cấu hình đó làm gì?
J86

31

Tình huống và lỗi tương tự này cũng có thể xảy ra với trình hướng dẫn mặc định được tạo proxy SOAP Web Service (không phải 100% nếu đây cũng là trường hợp trên System.ServiceModelngăn xếp WCF ) khi chạy:

  • máy người dùng cuối được định cấu hình (trong Cài đặt Internet) để sử dụng proxy không hiểu HTTP 1.1
  • khách hàng cuối cùng đã gửi một cái gì đó mà proxy HTTP 1.0 không hiểu (thường là một Expecttiêu đề như một phần của HTTP POSThoặc PUTyêu cầu do một quy ước giao thức chuẩn gửi yêu cầu thành hai phần như được nêu trong phần Ghi chú ở đây )

... mang lại một con số 417.

Như được đề cập trong các câu trả lời khác, nếu vấn đề cụ thể mà bạn gặp phải là Expecttiêu đề đang gây ra sự cố, thì vấn đề cụ thể đó có thể được giải quyết bằng cách tắt chuyển PUT / POST hai phần tương đối toàn cầu System.Net.ServicePointManager.Expect100Continue.

Tuy nhiên, điều này không khắc phục được vấn đề tiềm ẩn hoàn toàn - ngăn xếp vẫn có thể đang sử dụng những thứ cụ thể HTTP 1.1 như KeepAlives, v.v. (mặc dù trong nhiều trường hợp, các câu trả lời khác không bao gồm các trường hợp chính.)

Tuy nhiên, vấn đề thực tế là mã được tạo tự động giả định rằng bạn có thể sử dụng các phương tiện HTTP 1.1 một cách mù quáng vì mọi người đều hiểu điều này. Để dừng giả định này đối với proxy Dịch vụ web cụ thể, người ta có thể thay đổi ghi đè mặc định bên dưới HttpWebRequest.ProtocolVersiontừ mặc định 1.1 bằng cách tạo lớp Proxy dẫn xuất ghi đè như trong bài đăng này : -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;
    }
}

(nơi mà MyWSproxy của trình hướng dẫn Thêm tham chiếu web nhổ vào bạn.)


CẬP NHẬT: Đây là một impl tôi đang sử dụng trong sản xuất:

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
Tôi biết bạn đã đăng bài này cách đây khá lâu, nhưng Ruben, bạn là một người bảo vệ cuộc sống. Vấn đề này đã khiến tôi phát điên cho đến khi tôi tìm ra giải pháp của bạn và nó hoạt động hoàn hảo. Chúc mừng!
Christopher McAtackney

1
@ChrisMcAtackney Bạn được chào đón. Nó chắc chắn có vẻ xứng đáng với nỗ lực ghi lại nó vào thời điểm đó ... vấn đề chung đặt ra xung quanh việc trở thành vấn đề ưu tiên hàng đầu và chỉ làm phiền tôi cho đến khi tôi điều tra đúng - nhưng dường như không có nước ép google nào cho bên đó của vấn đề. và đó là một trong những bài viết của chap Attwood từ đó trở lại đã thúc đẩy tôi làm điều đó. (Một upvote với một nhận xét như thế này là BTW tuyệt vời)
Ruben Bartelink

1
Bổ sung tuyệt vời và ví dụ. Cảm ơn!
Fadi Chamieh

5

Biểu mẫu bạn đang cố gắng mô phỏng có hai trường, tên người dùng và mật khẩu không?

Nếu vậy, dòng này:

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

không đúng

bạn sẽ cần hai dòng như:

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

Biên tập:

Được rồi, vì đó không phải là vấn đề, một cách để giải quyết vấn đề này là sử dụng thứ gì đó như Fiddler hoặc Wireshark để xem thành công những gì được gửi đến máy chủ web từ trình duyệt, sau đó so sánh với những gì được gửi từ mã của bạn. Nếu bạn đang đi đến một cổng 80 bình thường từ .Net, Fiddler vẫn sẽ nắm bắt lưu lượng này.

Có thể có một số trường ẩn khác trên biểu mẫu mà máy chủ web đang mong đợi rằng bạn không gửi.


3

Giải pháp từ phía proxy, tôi gặp phải một số vấn đề trong quy trình bắt tay SSL và tôi đã buộc máy chủ proxy của mình gửi yêu cầu bằng HTTP / 1.0 để giải quyết vấn đề bằng cách đặt đối số này trong httpd.conf SetEnv force-proxy-request-1.0 1 SetEnv proxy-nokeepalive 1sau đó tôi gặp phải lỗi 417 Ứng dụng khách của tôi đang sử dụng HTTP / 1.1 và proxy buộc phải sử dụng HTTP / 1.0, vấn đề đã được giải quyết bằng cách đặt tham số này trong httpd.conf ở phía proxy RequestHeader unset Expect earlymà không cần thay đổi bất cứ điều gì ở phía máy khách, hy vọng điều này sẽ giúp .


2

Đối với Powershell, nó là

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

1

Nếu bạn đang sử dụng " HttpClient " và bạn không muốn sử dụng cấu hình toàn cầu để ảnh hưởng đến tất cả các chương trình bạn có thể sử dụng:

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

Tôi bạn đang sử dụng " WebClient " Tôi nghĩ bạn có thể thử xóa tiêu đề này bằng cách gọi:

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

0

Trong tình huống của tôi, lỗi này dường như chỉ xảy ra nếu máy tính của khách hàng của tôi có chính sách tường lửa nghiêm ngặt, điều này ngăn chương trình của tôi giao tiếp với dịch vụ web.

Vì vậy, giải pháp duy nhất tôi có thể tìm thấy là bắt lỗi và thông báo cho người dùng về việc thay đổi cài đặt tường lửa theo cách thủ công.


-1

Cách tiếp cận web.config hoạt động đối với các dịch vụ biểu mẫu InfoPath gọi đến các quy tắc kích hoạt dịch vụ web IntApp.

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

2
bản sao của stackoverflow.com/a/7353457/11635 Vui lòng bình luận ở đó nếu bạn muốn thêm một điểm
Ruben Bartelink
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.