Web 的基石:HTTP协议
Web 的基石:HTTP协议
一、HTTP 是什么?
HTTP(超文本传输协议,HyperText Transfer Protocol
) 是一个用于从网络服务器传输超文本(如网页)到本地浏览器(客户端)的应用层协议。它是互联网上数据通信的基础,也是万维网(WWW)的基石。
你可以把它想象成 “浏览器和服务器之间约定好的一种对话规则和语言”。
特点:
- 基于TCP协议:面向连接,安全
- 基于请求-响应模型的:一次请求对应一次响应
- HTTP协议是无状态的协议:对于事务处理没有记忆能力。每次请求-响应都是独立的。
· 缺点:多次请求间不能共享数据。
· 优点:速度快
二、HTTP请求协议
(1)请求数据格式
HTTP 请求报文结构(由三部分组成)
1.请求行 (Request Line)
位置:请求数据的第一行。
内容:包含三个核心部分:
- 请求方式:如
GET
、POST
、PUT
、DELETE
等。 - 资源路径:即请求的目标 URL 路径,如 /api/users。
- 协议:使用的 HTTP 协议版本,如 HTTP/1.1。
2.请求头 (Request Headers)
位置:从第二行开始,至一个空行结束。
格式:每一行都是一个键值对,格式为 Key: Value。
请求头字段 | 含义与示例 |
---|---|
Host | 请求的主机名 |
User-Agent | 浏览器版本,例如Chrome浏览器的标识类似Mozilla/5.0... Chrome/79 ,IE浏览器的标识类似Mozilla/5.0 (Windows NT ...) like Gecko |
Accept | 表示浏览器能接收的资源类型,如text/* ,image/* 或者*/* 表示所有 |
Accept-Language | 表示浏览器偏好的语言,服务器可以据此返回不同语言的网页 |
Accept-Encoding | 表示浏览器可以支持的压缩类型,例如gzip ,deflate 等 |
Content-Type | 请求主体的数据类型 |
Content-Length | 请求主体的大小(单位:字节) |
常见示例:
- Host:
www.example.com
;User-Agent:Mozilla/5.0...
;Content-Type:application/json
;Accept:*/*
3.请求体 (Request Body)
存在性:通常为 POST、PUT 等请求所特有,GET 请求一般没有请求体。
作用:用于存放要提交给服务器的请求参数。
格式:取决于请求头中的 Content-Type,常见的有:
application/json
(JSON 格式);application/x-www-form-urlencoded
(表单格式);multipart/form-data
(带文件上传的表单格式)
4.GET与POST的区别
特性 | GET 请求 | POST 请求 |
---|---|---|
语义 | 获取数据(安全操作) | 提交数据(非安全操作) |
参数位置 | URL 末尾(?key1=value1&key2=value2 ) | 请求体中(Body) |
数据长度限制 | ✅ 有(URL 最大 2KB~8KB) | ❌ 无(实际受服务器限制) |
安全性 | ❌ 低(参数暴露在地址栏/历史记录)http://xx.com/login?password=123 | ⚠️ 中(Body 不可见,但抓包可获取) |
幂等性 | ✅ 是(多次请求结果相同) | ❌ 否(多次提交可能产生副作用) |
缓存 | ✅ 可缓存 | ❌ 不可缓存 |
书签收藏 | ✅ 支持带参数收藏 | ❌ 仅保存路径 |
TCP 数据包 | 1 个(Header + Data 一起发送) | 2 个(先发 Header,服务器响应 100 Continue 后再发 Body) |
SpringBoot 注解 | @GetMapping + @RequestParam | @PostMapping + @RequestBody |
典型场景 | 搜索、页面跳转、资源下载 | 登录、支付、文件上传、数据修改 |
💡 黄金法则:
改变服务器状态的操作(创建/修改/删除)永远不要用 GET
敏感数据(密码/支付信息)必须用 POST + HTTPS
(2)请求数据获取
Web服务器(Tomcat)对HTTP协议的请求数据进行解析,并进行了封装(HttpServletRequest),在调用Controller方法的时候传递给了该方法。这样,就使得程序员不必直接对协议进行操作,让Web开发更加便捷。
用代码获取请求数据
在SpringBoot里面创建一个 RequestController.java类
package com.example.springbootweb1;
import com.sun.net.httpserver.HttpServer;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RequestController {
@RequestMapping("/request")
public String request(HttpServletRequest request) {
// 1.获取请求方式
String method = request.getMethod(); // GET
System.out.println("请求方式:" + method);
// 2.获取请求url地址
String url = request.getRequestURL().toString(); // http://localhost:8080/request
System.out.println("请求url地址:" + url);
// 获取请求uri地址
String uri = request.getRequestURI(); // /request
System.out.println("请求uri地址:" + uri);
// 3.获取请求协议
String protocol = request.getProtocol(); // HTTP/1.1
System.out.println("请求协议:" + protocol);
// 4.获取请求参数-name,age
String name = request.getParameter("name");
String age = request.getParameter("age");
System.out.println("name: " + name + ", age: " + age);
// 5.获取请求头-Accept
String accept = request.getHeader("Accept");
System.out.println("Accept: " + accept);
return "处理完成";
}
}
这段代码演示了如何使用 HttpServletRequest
对象获取HTTP
请求的各种信息,包括请求方法、URL、URI、协议版本、请求参数和请求头信息
接着我们启动项目输入这段网址
http://localhost:8081/request?name=whgckjxy&age=20
访问之后我们就可以在控制台接收到数据了
三、HTTP相应协议
(1)响应数据格式
1.响应行 (Status Line)
位置:响应数据的第一行。
内容:包含三个关键信息:
- 协议版本:如 HTTP/1.1
- 状态码:如 200、404、500等,用于简明告知客户端请求的结果。
- 状态描述:对状态码的简短文字说明,如 OK、Not Found。
代码 | 说明 |
---|---|
1xx | 响应中 - 临时状态码,表示请求已经接收,告诉客户端应该继续请求或者如果它已经完成则忽略它。 |
2xx | 成功 - 表示请求已经被成功接收,处理已完成。 |
3xx | 重定向 - 重定向到其他地方;让客户端再发起一次请求以完成整个处理。 |
4xx | 客户端错误 - 处理发生错误,责任在客户端。如:请求了不存在的资源、客户端未被授权、禁止访问等。 |
5xx | 服务器错误 - 处理发生错误,责任在服务端。如:程序抛出异常等。 |
示例:HTTP/1.1 200 OK
2.响应头 (Response Headers
)
位置:从第二行开始,到第一个空行结束。
格式:每一行都是一个键值对(Key: Value
),向客户端传递关于响应的附加信息。
常见头部示例:
Content-Type: text/html; charset=utf-8
(告知客户端响应体的数据类型和编码)Content-Length: 1024
(告知客户端响应体的数据大小)Set-Cookie: sessionId=abc123
(指示浏览器设置Cookie)
响应头字段 | 功能说明 |
---|---|
Content-Type | 表示该响应内容的类型(MIME类型),例如 text/html , application/json 。 |
Content-Length | 表示该响应内容的长度(单位:字节)。 |
Content-Encoding | 表示该响应内容使用的压缩算法,例如 gzip 。 |
Cache-Control | 指示客户端应如何缓存响应内容,例如 max-age=300 表示可以最多缓存300秒。 |
Set-Cookie | 告诉浏览器为当前页面所在的域设置Cookie。 |
3.响应体 (Response Body
)
位置:在响应头之后的一个空行下面。
内容:服务器返回给客户端的实际数据。这是最主要的部分。
常见内容:可以是网页的HTML代码、JSON数据、XML数据、图片文件等。
(2)响应数据设置
Web
服务器对HTTP
协议的响应数据进行了封装(HttpServletResponse
),并在调用Controller
方法的时候传递给了该方法。这样,就使得程序员不必直接对协议进行操作,让Web
开发更加便捷。
用代码获取请求数据
在SpringBoot里面创建一个 ResponseController.java类
package com.example.springbootweb1;
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 ResponseController {
@RequestMapping("/response")
public void response(HttpServletResponse response) {
//1. 设置响应状态码
response.setStatus(401);
//2. 设置响应头
response.setHeader("name", "Response");
//3. 设置响应体
try {
response.getWriter().write("<h1>hello response</h1>");
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
接着我们启动项目输入这段网址
http://localhost:8081/response
@RestController
public class ResponseController {
/**
* 方式一:使用HttpServletResponse原生对象设置响应数据
* 这是Servlet API的传统方式,需要手动处理响应状态码、头部和体
*
* @param response HttpServletResponse对象,用于设置响应参数
* @throws IOException 可能发生的IO异常
*/
@RequestMapping("/response")
public void response(HttpServletResponse response) throws IOException {
// 1. 设置响应状态码:401表示未授权
response.setStatus(401);
// 2. 设置响应头:添加自定义头部信息
response.setHeader("name", "Response");
// 3. 设置响应体:向客户端返回HTML内容
response.getWriter().write("<h1>hello response</h1>");
}
/**
* 方式二:使用ResponseEntity - Spring中提供的方式
* 这是Spring框架推荐的响应构建方式,提供链式调用和更优雅的API
*
* @return ResponseEntity对象,包含完整的响应信息
*/
@RequestMapping("/response2")
public ResponseEntity<String> response2() {
return ResponseEntity
.status(401) // 响应状态码:设置HTTP状态为401未授权
.header("name", "javaweb-ai") // 响应头:添加自定义头部name=javaweb-ai
.body("<h1>hello response</h1>"); // 响应体:设置返回的HTML内容
}
}
① 基于HttpServletResponse封装
@RequestMapping("/response")
public void response(HttpServletResponse response) throws IOException {
// 1. 设置响应状态码:401表示未授权
response.setStatus(401);
// 2. 设置响应头:添加自定义头部信息
response.setHeader("name", "Response");
// 3. 设置响应体:向客户端返回HTML内容
response.getWriter().write("<h1>hello response</h1>");
}
响应体
② 基于ResponseEntity封装
@RequestMapping("/response2")
public ResponseEntity<String> response2() {
return ResponseEntity
.status(401)
// 响应状态码:设置HTTP状态为401未授权
.header("name", "javaweb-ai")
// 响应头:添加自定义头部name=javaweb-ai
.body("<h1>hello response</h1>");
// 响应体:设置返回的HTML内容
}
响应体
注意:
响应状态码和响应头如果没有特殊要求的话,通常不手动设定。服务器会根据请求处理的逻辑,自动设置响应状态码和响应头。