上文(Http请求响应------请求Http概述 Http协议(HyperText Transfer Protocol,超文本传输协 - 掘金)提到Http中的请求,Http协议采用的是"请求-响应"模型
本文讲解Http中的响应。
Http响应
响应数据格式
首先先看一个简单的请求,请求www.baidu.com 然后百度的服务器会给我们响应什么数据:
这是请求www.baidu.com 时,百度的服务器接收到浏览器请求之后给浏览器响应回来的响应数据,这样一个响应数据和请求数据一样,也是由三个部分组成:
响应行
响应行是响应数据的第一行,其中包含Http协议版本、响应的状态码、响应状态码对应的描述信息 。如上图所示,请求百度之后,百度服务器返回的响应数据的响应行看出,这次请求使用的是Http协议
,版本是1.1;响应的状态码是200
,代表本次请求响应成功;描述状态码的信息是OK
,也是代表本次请求响应成功。
响应头
从响应数据的第二行开始,以key: value的格式出现 。用于提供有关响应的额外信息 ,比如内容类型、缓存控制
等,响应头信息是告诉客户端如何更好的处理响应内容、如何缓存资源等。
常见的响应头
Content-Type
指定响应内容的类型,比如text/html、application/json等。
Content-Length
指定响应体的大小(以字节为单位),我们可以看到请求www.baidu.com ,百度的服务器响应回来的响应体是一个Html的页面(也就是我们看到的百度):
Edge浏览器将响应体单独拿出来了,按理来说实际上响应体和请求体一样,在响应头的一个空行的下方。
Cache-Control
指定缓存策略
Server
指定响应所用的服务器软件(百度是BWS/1.1)
Location
在发生重定向时,指定新的URL,这里十分重要,下文会详细讲解
Set-Cookie
设置客户端的cookie
还有很多响应头,此处不一一列举,响应头的很多原理和请求头是一致的。
响应状态码
1XX
表示响应中
,是临时的状态码;表示请求已经接收了,告诉客户端应该继续请求或客户端已经完成则可以忽略(常见于WebSocket
技术)。
2XX
成功
,该请求已经被成功接收,并且也成功处理,其中200
是大家最想看见的。
3XX
重定向
,上文介绍Location响应头时提到过,表示重定向到其他地方了
,让客户端再次发起一次请求
可以完成整个处理。
比如:请求百度:http://www.baidu.com
,百度的请求路径是https://www.baidu.com
,但是请求也会成功 是因为第一次请求http的时候,百度的服务器能够接收,会响应一个307状态码,告诉浏览器需要重定向访问正确的百度 ,并且会在响应头中添加Location:https://www.baidu.com
这个响应头,浏览器就会根据这个响应的location 再次发起请求,这次就会成功请求到正确的百度 在重定向中,一共有两次请求响应的过程 ,第一次是请求到了错误的路径,但是服务器成功接收,返回3XX的状态码和在请求头中添加Location:(正确的路径) ;浏览器看到状态码是3XX,就会根据Location的路径发起第二次请求, 但是都是由浏览器在极短的时间内完成的,用户无法察觉。
4XX
客户端的错误,处理发生错误,责任在于客户端 。如:请求了不存在的资源、客户端未被授权、禁止访问等,常见404
。
5XX
服务器错误,处理发生错误,责任在于服务端 。如:客户端程序抛出了异常(500
就是服务器端抛异常了)。
HttpServletResponse
和HttpServletRequest
一样,Tomcat也封装了一个HttpServletResponse
对象,我们可以直接操作这个对象来修改响应数据:
java
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
@RestController
public class HttpController {
@RequestMapping("response")
public void response(HttpServletResponse response) throws IOException {
// 设置响应状态码
response.setStatus(302);
// 设置响应头
response.setHeader("Location", "https://www.baidu.com");
// 设置响应体
// 响应体需要使用流写入,HttpServletResponse中自带IO流,打开后就可以直接写
response.getWriter().write("<h1>Hello Response<h1>");
}
}
我们可以看到,在使用HttpServletResponse
类的时候,方法无需返回值,因为服务端会自动将HttpServletResponse
响应给客户端,我们将其状态码修改为302
,浏览器接收到响应数据时,解析后将重定向到Location
指定的URL:
并且,我们可以在响应体中写一些HTML的代码,浏览器会自动解析。
ResponseEntity
Spring框架还提供了一个ResponseEntity对象来完成同样的功能,更加简单,但是原理相同,此处不做过多赘述:
java
/**
* 除了Tomcat服务器的封装,Spring提供了操作响应数据的对象ResponseEntity,可以通过ResponseEntity对象
* 更加便捷的操作响应数据
*
* @return ResponseEntity
*/
@RequestMapping("/response2")
public ResponseEntity<String> response() {
return ResponseEntity.status(307)
.header("Location", "https://www.baidu.com")
.body("<h1>Spring Response<h1>");
}
// 但是需要注意的是:响应状态码(status)和响应头(header)没有特殊要求的话,通常不手动设置
// 服务器会根据请求处理的逻辑自动设置响应状态码和响应头