HTTP HEAD请求
HEAD请求是一种HTTP请求方法,与GET请求类似,但不返回响应正文主体,只返回响应头部信息。它通常用于获取与资源相关的元数据,如响应状态码、响应头部、最后修改时间等,而不需要传输实际的资源内容。HEAD请求经常被用来检查服务器是否可用、文件是否存在以及检查资源的更新时间戳等操作,其请求及响应报文如下所示:
请求报文:
HEAD / HTTP/1.1
Host: www.devzhi.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.82 Safari/537.36
Accept: */*
Accept-Encoding: gzip, deflate, br
Connection: keep-alive
响应报文:
HTTP/1.1 200 OK
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 13 Apr 2023 02:41:00 GMT
Content-Type: text/plain
Content-Length: 18
Connection: keep-alive
如何实现HEAD接口
Spring Boot
在Spring Boot中实现HEAD请求方法跟其他HTTP请求方法的实现方式基本相同,只需要在对应的Controller中定义一个使用@RequestMapping注解的方法,并设置其RequestMethod为HEAD即可。
举个例子,假设你要对某个请求路径”/example”实现HEAD请求方法,可以在Controller类中增加如下代码:
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class ExampleController {
@RequestMapping(value = "/example", method = RequestMethod.HEAD)
public ResponseEntity<Void> headExample() {
// 这里可以写一些业务逻辑
// 返回一个空的ResponseEntity,表示当前请求资源存在
return ResponseEntity.ok().build();
}
}
在上述代码中,我们在方法headExample()上标注了@RequestMapping注解,并将其RequestMethod设置为HEAD。在方法体中,我们可以编写一些业务逻辑来处理该请求,然后通过返回一个空的ResponseEntity来表示当前请求资源存在。
需要注意的是,由于HEAD请求方法不会返回具体的内容,因此在返回ResponseEntity时,我们只需要返回状态码即可。如果当前请求的资源不存在,我们可以返回404状态码。
除此之外,在Spring Boot中实现GET接口后HEAD接口会被自动实现,Spring Boot会自动为对应的请求路径生成HEAD请求的处理逻辑。这是因为HTTP协议规定,在没有明确指定HEAD请求处理逻辑的情况下,服务器应该使用GET请求的处理逻辑来处理HEAD请求。
因此,如果你已经在Controller中实现了对应的GET请求方法,就不需要再显式地为同样的请求路径编写HEAD请求方法了。当客户端发送HEAD请求时,Spring Boot会自动调用对应的GET请求方法,并忽略其返回值,只返回请求头信息。
在 Spring Boot 中,处理 HTTP 请求的核心组件是 DispatcherServlet。当收到一个请求时,DispatcherServlet 会根据请求路径和请求方法查找对应的 RequestMappingHandlerMapping 和 RequestMappingHandlerAdapter,并将请求交给它们进行处理。
RequestMappingHandlerMapping 负责查找匹配当前请求的 Controller 方法,而 RequestMappingHandlerAdapter 则负责调用 Controller 方法并将其返回结果转换为响应内容。在默认情况下,Spring Boot 使用 DefaultRequestMappingHandlerAdapter 和 RequestMappingHandlerMapping 来处理 HTTP 请求。
对于 HEAD 请求,DispatcherServlet 会先调用 RequestMappingHandlerMapping 的getHandler()
方法来查找对应的处理器(handler)。在这个方法中,RequestMappingHandlerMapping 会通过遍历所有已注册的 HandlerMethod,找到对应的 GET 请求的处理器方法,并使用它来处理当前 HEAD 请求。
具体而言,就是首先查找是否有对应的 GET 请求方法,然后将其包装成一个空的 ResponseBody,并设置响应头信息,最后返回这个 ResponseBody 对象。这样,客户端就能够得到与 GET 请求相同的响应头信息,但是不会获取到响应正文内容。
如果在当前路径下没有对应的 GET 请求方法,则会返回一个 404 Not Found 响应。
下面是一个简化版的代码示例,展示了 Spring Boot 如何处理 HEAD 请求:
public class RequestMappingHandlerMapping {
public Object getHandler(HttpServletRequest request) {
// 查找当前请求的处理器方法
HandlerMethod handlerMethod = findHandlerMethodForRequest(request);
if (handlerMethod != null) {
// 找到了对应的处理器方法,使用它来处理 HEAD 请求
if ("HEAD".equals(request.getMethod())) {
return new HandlerMethodReturnValueHandlerComposite().handleReturnValue(
new ResponseEntity<>(null, handlerMethod.getResponseHeaders(), HttpStatus.OK),
handlerMethod,
new ServletWebRequest(request)
);
}
// ...其他请求方法的处理逻辑
}
// 没有找到合适的处理器方法,返回 404 Not Found 响应
return new ResponseEntity(HttpStatus.NOT_FOUND);
}
// ...其他辅助方法
}
在上述代码中,当 DispatcherServlet 收到一个 HEAD 请求时,会调用 RequestMappingHandlerMapping 的getHandler()
方法进行处理。
如果存在对应的 GET 请求方法,RequestMappingHandlerMapping 就会将其包装成一个空的 ResponseBody 对象,并设置响应头信息,最终返回这个对象作为响应结果。如果没有找到对应的 GET 方法,则会直接返回一个 404 Not Found 响应。
Gin
与 Spring Boot 不同,Gin 框架不会自动为 GET 请求生成 HEAD 请求的处理方法。因此,如果要支持 HEAD 请求,你需要为对应的请求路径显式地编写一个处理 HEAD 请求的函数。
举个例子,假设你要对某个请求路径”/example”实现 HEAD 请求方法,可以在路由中增加如下代码:
import "github.com/gin-gonic/gin"
func main() {
r := gin.Default()
r.GET("/example", func(c *gin.Context) {
// 这里是 GET 请求的业务逻辑
c.String(http.StatusOK, "Hello, GET request!")
})
r.HEAD("/example", func(c *gin.Context) {
// 这里是 HEAD 请求的业务逻辑
c.Status(http.StatusOK)
})
r.Run(":8080")
}
如何使用curl发送HEAD请求
curl是一个非常强大的命令行工具,可以用来向服务器发送HTTP请求。要发送HEAD请求,只需使用”-I”选项即可。以下是一个使用curl发送HEAD请求的示例:
curl -I https://www.devzhi.com
上述命令将向http://www.devzhi.com
发送一个HEAD请求,如果该资源存在,则服务器将返回响应头部信息。
$ curl -I https://www.devzhi.com
HTTP/1.1 404 Not Found
Server: nginx/1.18.0 (Ubuntu)
Date: Thu, 13 Apr 2023 02:52:52 GMT
Content-Type: text/plain
Content-Length: 18
Connection: keep-alive
注意到了吗,返回了404,因为目前我的博客是使用gin来实现的,而我没有去实现HEAD接口,这也是对前文关于Gin框架介绍部分的一个实际演示,什么?为什么文章一开头返回的是200 OK
?,那当然是为了把文章写下去啊。
HEAD请求的应用场景
-
检查资源是否存在:当你需要检查一个资源是否存在时,使用HEAD请求可以返回该资源的状态码和相关头信息,而无需下载整个资源。
-
获取资源的元数据:有时候,我们只需要获取资源的元数据,比如最后修改时间、大小等信息。HEAD请求可以帮助我们在不下载整个资源的情况下获取这些信息。
-
验证资源是否被修改:在某些情况下,我们需要在资源被修改后更新缓存。使用HEAD请求可以让我们检查资源的最后修改时间,从而判断是否需要更新缓存。
-
确认链接是否有效:当您需要在网站中创建链接时,使用HEAD请求可以验证链接是否指向有效的资源,本站对友情链接的检测便是采用的HEAD请求。