我知道doHead方法不会通过http发送body,但是doGet方法也不会。 这两者之间有明确的区别吗? 谢谢。
简短回答
HEAD方法只会发送与GET请求相同的头部信息,但不包含实体主体。GET方法会发送这些头部信息和实体主体。当然,在极少数或有争议的情况下,如果GET方法在其主体中什么都不发送,那么GET方法和HEAD方法行为将相似。
书籍《HTTP 权威指南》补充道:
这让客户端能够检查资源的标题,而无需实际获取资源。使用HEAD方法,您可以:
- 了解资源(例如,确定其类型)而无需获取它。
- 通过查看响应的状态代码来查看对象是否存在。
- 通过查看标头测试资源是否已修改。
服务器开发人员必须确保返回的头部正是GET请求会返回的头部。 HEAD方法也是符合HTTP / 1.1要求的。
因此,doHead
是否调用doGet
可能只是一个实现细节,但如果是这样,doHead
需要在发送响应之前删除doGet
的主体。但这种实现是低效的,因为理想情况下,doHead
不应该承担执行整个doGet
请求以确定要发送哪些头部的困难。
某些头部的计算可能会带来一些困难。例如,“Content-Length”头需要我们知道实际资源的大小,因此HEAD方法可能需要“获取”资源以确定相应GET请求的字节数大小,但它不会使网络负担过重,也不会将资源发送回来,尽管它可能会使服务器负担加重,以便确定要发送哪些头部(即Content-Length、Content-Type、Content-Language等)
详细回答
HTTP规范中提到:
9.4 HEAD
HEAD方法与GET方法相同,但服务器不得在响应中返回消息正文。响应头中包含的元信息应与响应GET请求时发送的信息相同。此方法可用于获取有关请求所涉及的实体的元信息,而无需传输实体正文本身。此方法经常用于测试超文本链接的有效性、可访问性和最近修改。
对HEAD请求的响应可以被缓存,因为响应中包含的信息可以用于从该资源更新先前缓存的实体。如果新字段值表明缓存的实体与当前实体不同(如Content-Length、Content-MD5、ETag或Last-Modified的更改所示),则缓存必须将缓存条目视为过期。
而对于GET,则说:
9.3 GET
GET方法表示检索由请求URI标识的任何信息(以实体形式)。如果请求URI引用数据生成过程,则应该将生成的数据作为响应中的实体返回,而不是该过程的源文本,除非该文本恰好是该过程的输出。
如果请求消息包括If-Modified-Since、If-Unmodified-Since、If-Match、If-None-Match或If-Range头字段,则GET方法的语义将更改为“条件GET”。条件GET方法请求仅在由条件头字段描述的情况下传输实体。条件GET方法旨在通过允许刷新缓存的实体而无需多次请求或传输客户端已持有的数据来减少不必要的网络使用。
如果请求消息包括Range头字段,则GET方法的语义将更改为“部分GET”。部分GET请求仅传输实体的一部分,如第14.35节所述。部分GET方法旨在通过允许完成部分检索的实体而无需传输客户端已持有的数据来减少不必要的网络使用。
只有满足第13节中描述的HTTP缓存要求的响应才可以被缓存。
有关表单使用时的安全性,请参见第15.1.3节。
如果您查看javax.servlet.http.HttpServlet
的源代码,您会发现其文档说:
protected void doHead(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException
{
NoBodyResponse response = new NoBodyResponse(resp);
doGet(req, response);
response.setContentLength();
}
NoBodyResponse
的代码,你会发现它只是一个响应,其输出流会丢弃所有数据,并仅计算字节数以确定相应GET响应的正确Content-Length。因此,这是Servlet规范建议如何生成有效的HEAD响应的方式。只要遵循HTTP规范指南,你可以覆盖此行为以使其更加高效。