HEAD 只发回与相应 GET 请求相同的header信息,但没有实体主体。 GET 将发送相同的标头和实体主体。当然,在特殊情况下,GET 不会在其body中发回任何内容,那么 GET 和 HEAD 的行为类似。
《HTTP The Definitive Guide 》的说法
doHead允许客户端检查资源的header,而无需实际获取资源。使用 HEAD可以:
- 在不获取资源的情况下找出资源(例如,确定其类型)。
- 通过查看响应的状态代码来查看对象是否存在。
- 通过查看header来测试资源是否已被修改。
服务器开发人员必须确保返回的标头与 GET 请求返回的标头完全相同。 HEAD 方法也是 HTTP/1.1 合规性所必需的。
因此,doHead 是否调用 doGet 可能只是一个实现细节,但如果是这样,doHead 需要在发送响应之前剥离 doGet 的body。不过,这种实现效率很低,因为理想情况下,doHead 不应在执行整个 doGet 请求来确定要发回哪些header。
不过,某些header的计算可能会带来困难。例如,“Content-Length”标头意味着我们需要知道实际资源的大小,因此 HEAD 可能需要“GET”资源来确定相应 GET 请求的实际大小(以字节为单位),但这不会造成负担网络实际发送回资源,尽管它可能会给服务器带来资源检索的负担,以确定发送回哪些标头(即内容长度、内容类型、内容语言等)
HttpServlet 里面的源码
/**
*
*
* <p>
* Receives an HTTP HEAD request from the protected <code>service</code> method and handles the request. The client
* sends a HEAD request when it wants to see only the headers of a response, such as Content-Type or Content-Length. The
* HTTP HEAD method counts the output bytes in the response to set the Content-Length header accurately.
*
* <p>
* If you override this method, you can avoid computing the response body and just set the response headers directly to
* improve performance. Make sure that the <code>doHead</code> method you write is both safe and idempotent (that is,
* protects itself from being called multiple times for one HTTP HEAD request).
*
* <p>
* The default implementation calls {@link #doGet(HttpServletRequest, HttpServletResponse)}. If the
* {@link ServletConfig} init parameter {@link #LEGACY_DO_HEAD} is set to "TRUE", then the response instance is wrapped
* so that the response body is discarded.
*
* <p>
* If the HTTP HEAD request is incorrectly formatted, <code>doHead</code> returns an HTTP "Bad Request" message.
*
* @param req the request object that is passed to the servlet
*
* @param resp the response object that the servlet uses to return the headers to the clien
*
* @throws IOException if an input or output error occurs
*
* @throws ServletException if the request for the HEAD could not be handled
*/
protected void doHead(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
if (legacyHeadHandling) {
NoBodyResponse response = new NoBodyResponse(resp);
doGet(req, response);
response.setContentLength();
} else {
doGet(req, resp);
}
}
通过阅读 NoBodyResponse 的代码,会发现它只是一个响应,其输出流丢弃所有数据,并且仅计算字节数以确定相应 GET 响应的正确内容长度。