HTTP 协议
- [HTTP 协议在协议栈中的位置](#HTTP 协议在协议栈中的位置)
- [HTTP 请求-响应模式](#HTTP 请求-响应模式)
- [HTTP 报文结构](#HTTP 报文结构)
-
- [HTTP 请求报文详解(Request)](#HTTP 请求报文详解(Request))
-
- [1. 首行(请求行)](#1. 首行(请求行))
-
- URL⭐
- [HTTP 方法(Method)](#HTTP 方法(Method))
- [GET 和 POST 的核心区别⭐](#GET 和 POST 的核心区别⭐)
- [HTTP 版本](#HTTP 版本)
- [2. 请求头(Request Header)⭐](#2. 请求头(Request Header)⭐)
-
- Host
- Connection
- User-Agent(UA)
- Accept
- Referer
- Cookie
- [Content-Type + Content-Length](#Content-Type + Content-Length)
- [3. 空行](#3. 空行)
- [4. 正文(Body)](#4. 正文(Body))
- [HTTP 响应报文详解(Response)](#HTTP 响应报文详解(Response))
-
- [1. 首行(状态行)](#1. 首行(状态行))
- [2. 响应头(Response Header)](#2. 响应头(Response Header))
- [3. 空行](#3. 空行)
- [4. 正文(Body)](#4. 正文(Body))
- [服务器如何解析 HTTP 报文?](#服务器如何解析 HTTP 报文?)
- HTTPS
HTTP 协议在协议栈中的位置
HTTP 属于应用层协议,是当前 Web 开发中最核心的协议。
TCP/IP 分层模型
OSI 参考模型
应用层
表示层
会话层
传输层
网络层
数据链路层
物理层
应用层 - HTTP/DNS/SSH/FTP...
传输层 - TCP/UDP
互联网层 - IP/ICMP/ARP
网卡层/硬件
HTTP 请求-响应模式
HTTP 是一问一答模式的协议,客户端发一个请求,服务器返回一个响应,严格一一对应。
🖥️ 服务器 🖥️ 客户端 🖥️ 服务器 🖥️ 客户端 请求 = 首行 + 请求头 + 空行 + 正文 响应 = 首行 + 响应头 + 空行 + 正文 ⚠️ 必须先有请求,才有响应 服务器不能主动推送消息给客户端 📤 HTTP请求 1:GET /index.html 📥 HTTP响应 1:200 OK + HTML 页面 📤 HTTP请求 2:POST /api/login 📥 HTTP响应 2:200 OK + 登录结果
四个关键特点:
| 特点 | 说明 |
|---|---|
| 单向发起 | 只能由客户端主动发起请求,服务器被动等待 |
| 一一对应 | 一个请求必定对应一个响应(即使响应内容为空) |
| 同步完成 | 在一个请求-响应周期内,客户端等待服务器处理后才能继续 |
| 无状态 | 每次请求都是独立的,服务器不记得之前处理过什么 |
Q:HTTP 为什么选择请求-响应模式?
HTTP 协议设计之初主要为了 Web 文档的传输,场景相对简单,因此选择最基础的一问一答模式,原因如下:
- 实现简单:客户端请求,服务器响应,逻辑清晰
- 无状态特性:每个请求独立,服务器无需维护连接状态,扩展性好
- 符合 Web 场景:用户点击链接 → 浏览器请求页面 → 服务器返回页面,天然匹配
- 易于缓存:响应可缓存,减少重复请求
HTTP 报文结构
HTTP 报文分为请求报文 和响应报文两种,但两者的结构非常相似,都由四个部分组成:
HTTP 报文通用结构
第一部分
起始行
(Start Line)
第二部分
头部字段
(Header)
第三部分
空行
(Empty Line)
第四部分
报文主体
(Body)
请求报文与响应报文对比
通过网络传输
📥 HTTP 响应报文(完整示例)
首行(状态行)
HTTP/1.1 200 OK
响应头
Server: Nginx
Content-Type: application/json
Content-Length: 98
Set-Cookie: sessionId=xyz789
空行
\\r\
正文
{'code': 200, 'msg': '登录成功', 'token': 'xxx'}
📤 HTTP 请求报文(完整示例)
首行(请求行)
POST /api/login HTTP/1.1
请求头
Host: www.example.com
Content-Type: application/json
Content-Length: 52
User-Agent: Chrome/120
空行
\\r\
正文
{'username': 'admin', 'password': '123456'}
HTTP 请求报文详解(Request)
1. 首行(请求行)
格式 :方法 URL 版本号
示例:
GET /index.html HTTP/1.1
GET https://www.baidu.com/content-search.xml HTTP/1.1
POST /api/login HTTP/1.1
DELETE /user/1000 HTTP/1.1
三部分说明:
| 组成部分 | 说明 | 常见取值 |
|---|---|---|
| 方法 | 表示要对资源执行的操作 | GET、POST、PUT、DELETE、HEAD、OPTIONS 等 |
| URL | 要访问的资源路径 | /index.html、/api/user、/search?q=java |
| 版本号 | HTTP 协议版本 | HTTP/1.0、HTTP/1.1、HTTP/2.0 |
URL⭐
HTTP 方法(Method)
| 方法 | 说明 | 支持的 HTTP 版本 |
|---|---|---|
| GET | 获取资源 | 1.0、1.1 |
| POST | 传输实体主体 | 1.0、1.1 |
| PUT | 传输文件 | 1.0、1.1 |
| HEAD | 获得报文首部 | 1.0、1.1 |
| DELETE | 删除文件 | 1.0、1.1 |
| OPTIONS | 询问支持的方法 | 1.1 |
| TRACE | 追踪路径 | 1.1 |
| CONNECT | 要求用隧道协议连接代理 | 1.1 |
GET 和 POST 的核心区别⭐
| GET | POST | |
|---|---|---|
| 语义 | 获取数据 | 提交数据 |
| 数据位置 | 数据放在 URL 的 Query String 中 | 数据放在请求体(Body)中 |
| 安全性 | 参数暴露在 URL 中,不适合传敏感信息 | 参数在 Body 中,相对隐蔽(但需 HTTPS 才真正安全) |
| 数据长度 | URL 长度有限制(浏览器/服务器限制,通常 2KB~8KB) | Body 没有明确长度限制,可传大量数据 |
| 缓存 | 可以被浏览器缓存、保存到历史记录 | 默认不会被缓存 |
| 书签 | 可以收藏为书签 | 不能收藏为书签 |
- GET:能缓存、能收藏、参数在 URL 里、用来拿数据
- POST:不缓存、不收藏、参数在 Body 里、用来提交数据
HTTP 版本
| 版本 | 发布时间 | 现状 |
|---|---|---|
| HTTP/1.1 | 1997-1999 | 目前最主流 |
| HTTP/2.0 | 2012-2014 | 普及程度不高 |
| HTTP/3.0 | 最新 | 最新版本 |
HTTP/1.1 虽然是 20 多年前的协议,但仍然是目前最流行的版本。
2. 请求头(Request Header)⭐
格式 :字段名: 字段值,每行一个键值对
示例:
Host: www.baidu.com
Connection: keep-alive
sec-ch-ua-platform: "Windows"
is_referer: https://www.baidu.com/
Ps-Dataurlconfigqid: 0xac5268e3000021c4
sec-ch-ua: "Google Chrome";v="147", "Not.A/Brand";v="8", "Chromium";v="147"
sec-ch-ua-mobile: ?0
is_xhr: 1
X-Requested-With: XMLHttpRequest
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36
Accept: */*
Sec-Fetch-Site: same-origin
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Referer: https://www.baidu.com/s?wd=12306&rsv_spt=1&rsv_iqid=0...
Accept-Encoding: gzip, deflate, br, zstd
Accept-Language: zh-HK,zh-TW;q=0.9,zh;q=0.8
Cookie: BIDUPSID=0FAA43B5F92CE09FCF9F809C3032B273; PSTM=1745292309....
Host
| 字段名 | 说明 |
|---|---|
| Host | 目标服务器的主机名和端口号,即使使用了代理,也能通过 Host 获取原始目标。 |
Connection
| 字段名 | 说明 |
|---|---|
| Connection | 连接管理方式 keep-alive(长连接)/ close(短连接) |
服务器 客户端 服务器 客户端 keep-alive(长连接) 连接保持,不用重复握手 TCP 三次握手 请求1 响应1 请求2 响应2 请求3 响应3
User-Agent(UA)
| 字段名 | 说明 |
|---|---|
| User-Agent | 标识客户端信息(操作系统、浏览器版本等),可用于区分用户设备,返回不同版本的页面。 |
Accept
| 字段名 | 说明 |
|---|---|
| Accept | 客户端能接收的数据类型: */*表示客户端接受任何类型的响应数据 |
Referer
| 字段名 | 说明 |
|---|---|
| Referer | 描述当前页面的来源,即用户从哪个页面跳转而来。直接输入 URL 或从收藏夹打开的页面没有 Referer。 |
Cookie
Content-Type + Content-Length
Content-Length表示 Body 中的数据长度
| 字段名 | 说明 | 示例 |
|---|---|---|
| Content-Length | 请求体的数据长度(字节) | Content-Length: 348 |
Content-Type表示 Body 中的数据格式,提示接收方如何解析数据。
| Content-Type | 对应数据格式 |
|---|---|
| text/html | HTML 网页 |
| text/css | CSS 样式 |
| application/javascript | JavaScript |
| application/json | JSON 数据 |
| image/png | PNG 图片 |
| image/jpg | JPG 图片 |
3. 空行
就是一个纯粹的换行符 \r\n(回车+换行),作用是将头部和主体分隔开。
这是 HTTP 协议设计的关键分隔符,服务器通过识别这个空行来判断头部的结束位置。
4. 正文(Body)
注意:不是所有请求都有 Body,例如 GET 请求通常没有 Body,数据放在 URL 的 Query String 中;而 POST、PUT 请求通常会把数据放在 Body 中。
客户端发送数据到服务器,主要通过 Content-Type 头声明格式。
| 格式大类 | MIME 类型(Content-Type) | 常见场景 | 数据示例/说明 |
|---|---|---|---|
| 表单格式 | application/x-www-form-urlencoded |
普通表单提交、页面POST | user=John&age=30 (类似URL参数,键值对) |
multipart/form-data |
包含文件上传的表单 | 分段数据,每段可包含独立头信息,能承载二进制文件 | |
| 文本格式 | application/json |
现代API (RESTful) | {"userId":1000,"position":"75E75N"} |
application/xml / text/xml |
传统企业服务 (如 SOAP) | <user><id>1000</id></user> |
|
text/plain |
发送纯文本日志/消息 | This is plain text. |
|
| 二进制/文件 | application/octet-stream |
上传单个文件(通用) | 原始二进制文件流 |
image/png, audio/mpeg 等 |
直接上传特定类型媒体文件 | 图片、音频等文件的二进制数据 |
HTTP 响应报文详解(Response)
1. 首行(状态行)
格式 :版本号 状态码 状态码描述
示例:
HTTP/1.1 200 OK
HTTP/1.1 404 Not Found
HTTP/1.1 500 Internal Server Error
三部分说明:
| 组成部分 | 说明 |
|---|---|
| 版本号 | HTTP 协议版本,如 HTTP/1.1 |
| 状态码 | 三位数字,表示请求的处理结果 |
| 状态码描述 | 状态码的简短文字说明 |
常见状态码
| 状态码 | 含义 | 说明 |
|---|---|---|
| 200 | OK | 请求成功 |
| 301 | Moved Permanently | 永久重定向 |
| 302 | Found | 临时重定向 |
| 304 | Not Modified | 资源未修改,使用缓存 |
| 400 | Bad Request | 请求有误 |
| 401 | Unauthorized | 未授权,需要登录 |
| 403 | Forbidden | 访问被拒绝,没有权限 |
| 404 | Not Found | 资源未找到 |
| 405 | Method Not Allowed | 请求方法与服务器注解不匹配 |
| 500 | Internal Server Error | 服务器内部错误,代码抛异常未catch |
| 502 | Bad Gateway | 网关错误 |
| 503 | Service Unavailable | 服务不可用 |
| 504 | Gateway Timeout | 网关超时,入口服务器响应超时 |
| 状态码大类 | 含义 | 说明 |
|---|---|---|
| 2xx | 成功 | 都可以视为是成功 |
| 3xx | 重定向 | 都是重定向 |
| 4xx | 客户端出错 | 用户构造的请求有问题 |
| 5xx | 服务端出错 | 服务器端出了问题 |
2. 响应头(Response Header)
示例:
Server: Nginx/1.20.0
Content-Type: text/html; charset=utf-8
Content-Length: 2048
Set-Cookie: sessionId=abc123; Path=/; HttpOnly
Cache-Control: max-age=3600
Date: Mon, 15 Jan 2024 08:30:00 GMT
常见响应头字段详解:
| 字段名 | 说明 | 示例 |
|---|---|---|
| Server | 服务器软件信息 | Server: Nginx/1.20.0 |
| Content-Type | 响应体的数据格式 | Content-Type: text/html; charset=utf-8 |
| Content-Length | 响应体的数据长度(字节) | Content-Length: 2048 |
| Set-Cookie | 要求浏览器设置 Cookie | Set-Cookie: sessionId=abc123 |
| Cache-Control | 缓存策略 | Cache-Control: max-age=3600 |
| Location | 重定向的目标 URL | Location: https://www.new-url.com |
| Date | 响应生成的时间 | Date: Mon, 15 Jan 2024 08:30:00 GMT |
3. 空行
与请求报文相同,使用 \r\n 分隔头部和主体。
4. 正文(Body)
服务器返回资源给客户端,浏览器根据 Content-Type 决定渲染、播放还是下载。
| 格式大类 | MIME 类型(Content-Type) | 常见场景 | 浏览器处理方式说明 |
|---|---|---|---|
| 超文本/网页 | text/html |
网页页面 | 直接渲染成网页 |
text/css |
样式文件 | 解析并应用样式 | |
| API 数据 | application/json |
前后端数据交互 | 代码处理,如 JavaScript 解析成对象 |
application/xml / text/xml |
RSS 订阅、数据导出 | 解析 XML 结构 (或触发下载) | |
| 媒体文件 | image/jpeg, image/png 等 |
显示图片 | 浏览器内直接展示 |
audio/mpeg |
播放音频 | 调起音频播放器 | |
video/mp4 |
播放视频 | 调起视频播放器 | |
| 文件/下载 | application/pdf |
预览PDF | 在浏览器内嵌阅读或下载 |
application/zip |
压缩包 | 触发下载行为 | |
application/octet-stream |
强制下载 | 触发下载,常配合 Content-Disposition 头指定文件名 |
|
| 脚本/资源 | application/javascript |
JS脚本 | 解析并执行 JavaScript 代码 |
服务器如何解析 HTTP 报文?
由于 HTTP 基于 TCP 协议,TCP 是面向字节流的,一个连接上可能连续发送多个请求。服务器必须明确一个请求从哪里开始、到哪里结束:
否
是
❌ 无 Body
(GET/HEAD/DELETE)
✅ 有 Body
(POST/PUT)
🔍 服务器收到 TCP 数据流
逐行读取数据
解析首行
获取方法、URL、版本号
继续逐行读取 Header
是否读到空行?
请求是否有 Body?
✅ 请求解析完成
读取 Content-Length 的值
继续读取 N 个字节
作为 Body 数据
- 无 Body 的请求(如 GET):读到空行即表示请求结束
- 有 Body 的请求 (如 POST):先解析头部获取
Content-Length,再根据这个值读取指定长度的 Body 数据
HTTPS
HTTPS=HTTP+SSL/TLS
【Java EE】 HTTPS协议