一個關於Http的請求頭Expect
分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow
也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!
轉載:http://blog.csdn.net/silence1214/article/details/6647421
經過分析就是多了個expect的請求頭,對方伺服器就報404的錯誤。我仔細看了下這個請求頭
,這裡有篇文章很詳細了,我轉發吧:
轉的哈:
這兩天寫程式碼,呼叫新浪微博的Rest API,使用HttpClient 4.0,以Post方式提交,請求引數以UrlEncodedFormEntity的形式設定到HttpPost物件中,提交到API時,出現如下異常:
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html> <head> <title>417 Expectation Failed</title> </head> <body> <h1>Error 417 Expectation Failed</h1> <p>Expectation Failed</p> <h3>Guru Meditation:</h3> <p>XID: 2734998565</p> <address> <a href="http://www.varnish-cache.org/">Varnish</a> </address> </body> </html>
剛開始有點莫名其妙,這是哪門子錯誤,沒見過啊,於是去查HTTP狀態字定義,得到如下描述:
The expectation given in an Expect request-header field (see section 14.20) could not be met by this server, or, if the server is a proxy, the server has unambiguous evidence that the request could not be met by the next-hop server.
大致的意思是:
伺服器不支援Expect請求頭部域,或者,如果伺服器是代理伺服器的話, 伺服器有明確的證據表明請求不能到達下一跳伺服器。
那,到底什麼是Expect請求頭部域呢?以前完全沒用過,也很少見,跟蹤瀏覽器的HTTP請求的時候也很少見這個頭部域,繼續查吧,根據HTTP請求頭部Expect域的定義,得到如下資訊:
The Expect request-header field is used to indicate that particular server behaviors are required by the client. Expect = "Expect" ":" 1#expectation expectation = "100-continue" | expectation-extension expectation-extension = token [ "=" ( token | quoted-string ) *expect-params ] expect-params = ";" token [ "=" ( token | quoted-string ) ] A server that does not understand or is unable to comply with any of the expectation values in the Expect field of a request MUST respond with appropriate error status. The server MUST respond with a 417(Expectation Failed) status if any of the expectations cannot be met or, if there are other problems with the request, some other 4xx status. This header field is defined with extensible syntax to allow for future extensions. If a server receives a request containing an Expect field that includes an expectation-extension that it does not support, it MUST respond with a 417 (Expectation Failed) status. Comparison of expectation values is case-insensitive for unquoted tokens (including the 100-continue token), and is case-sensitive for quoted-string expectation-extensions. The Expect mechanism is hop-by-hop: that is, an HTTP/1.1 proxy MUST return a 417 (Expectation Failed) status if it receives a request with an expectation that it cannot meet. However, the Expect request-header itself is end-to-end; it MUST be forwarded if the request is forwarded. Many older HTTP/1.0 and HTTP/1.1 applications do not understand the Expect header.
大致意思如下:
Expect請求頭部域,用於指出客戶端要求的特殊伺服器行為。若伺服器不能理解或者滿足 Expect域中的任何期望值,則必須返回417(Expectation Failed)狀態,或者如果請求 有其他問題,返回4xx狀態。 這個頭部域使用可擴充套件語法定義,以方便將來擴充套件。如果伺服器收到包含Expect頭部域的 請求且包含一個它不支援的期望值擴充套件,則必須返回417(Expectation Failed)狀態。 期望值的比較,對於非引用符號(包括100-continue)是大小寫無關的,對於引用字串 的期望值擴充套件,則是大小寫敏感的。 Expect域的機制是逐跳進行的,也就是說如果一個代理伺服器收到包含不能滿足的期望 的請求時,必須返回417(Expectation Failed)狀態。而Expect請求頭部域自身, 卻是端到端的,如果請求被轉發,則它也必須被轉發。 很多舊的HTTP/1.0和HTTP/1.1應用不支援Expect頭部。
到這裡,基本明白了為什麼會出現這樣的錯誤,說明程式碼最後生成的HTTP請求,包含了伺服器不能處理的Expect頭部,到底是什麼?裝上Wireshark,監聽一下請求內容,發現出現異常時的請求中的Expect頭部是這樣的:Expect:100-Continue,難道是它引起的?繼續查……
對於Expect:100-Continue,HttpClient的官方文件是這樣描述的:
The purpose of the Expect: 100-Continue handshake is to allow the client that is sending a request message with a request body to determine if the origin server is willing to accept the request (based on the request headers) before the client sends the request body. Expect: 100-continue handshake should be used with caution, as it may cause problems with HTTP servers and proxies that do not support HTTP/1.1 protocol.
大意如下:
Expect:100-Continue握手的目的,是為了允許客戶端在傳送請求內容之前,判斷源伺服器是否願意接受 請求(基於請求頭部)。 Expect:100-Continue握手需謹慎使用,因為遇到不支援HTTP/1.1協議的伺服器或者代理時會引起問題。
而HttpClient 4.0中,是否啟用Expect:100-Continue,是由HTTP請求執行引數http.protocol.expect-continue來控制的,通過設定引數值為true或者false,可以相應的啟用或者關閉Expect:100-Continue握手。注意,在HttpClient中,預設是啟用的。
HttpClient 4 中關閉Expect:100-Continue握手的程式碼如下:
- HttpPost httpPost <span style="color:#339933">=</span> <span style="color:#000000; font-weight:bold">new</span> HttpPost<span style="color:#009900">(</span>url<span style="color:#009900">)</span><span style="color:#339933">;</span>
- httpPost.<span style="color:#006633">getParams</span><span style="color:#009900">(</span><span style="color:#009900">)</span>.<span style="color:#006633">setBooleanParameter</span><span style="color:#009900">(</span>CoreProtocolPNames.<span style="color:#006633">USE_EXPECT_CONTINUE</span>,
- <span style="color:#000066; font-weight:bold">false</span><span style="color:#009900">)</span><span style="color:#339933">;</span>
關閉HttpClient中的Expect:100-Continue握手之後,再執行程式,順利地通過微博API發出了一條訊息。
總結:通過這次的問題解決,可以看出,對於HTTP協議不夠熟悉,底層瞭解不夠,同時沒有認真閱讀HttpClient開發文件。我想,現在從事軟體開發行業的大部分人都或多或少有這樣的問題,即忽視底層協議及原理的學習。真正的瞭解底層原理,藉以開原始碼及開發文件的輔助,這樣才會能夠實現快速、高效、穩定的程式開發。