一个关于Http的请求头Expect

来源:互联网 发布:雅米网络兼职是真的吗 编辑:程序博客网 时间:2024/04/19 07:14

转载: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握手的代码如下:

[java] view plaincopy
  1. 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>  
  2. 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>,  
  3. <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开发文档。我想,现在从事软件开发行业的大部分人都或多或少有这样的问题,即忽视底层协议及原理的学习。真正的了解底层原理,借以开源代码及开发文档的辅助,这样才会能够实现快速、高效、稳定的程序开发。