1. OSI 七层网络模型
层级 | 名称 | 核心功能 | 协议示例 | 数据单元 |
---|---|---|---|---|
7 | 应用层 | 提供用户接口和网络服务 | HTTP, FTP, SMTP, DNS | 报文 |
6 | 表示层 | 数据格式转换、加密/解密、压缩/解压 | SSL, JPEG, MPEG | 数据流 |
5 | 会话层 | 建立、管理和终止会话连接 | NetBIOS, RPC | 会话数据 |
4 | 传输层 | 端到端可靠传输、流量控制、差错校验 | TCP, UDP | 数据段 |
3 | 网络层 | 路由选择、逻辑寻址、分组转发 | IP, ICMP, OSPF | 数据包 |
2 | 数据链路层 | 物理寻址、帧同步、差错控制 | Ethernet, PPP | 帧 |
1 | 物理层 | 比特流传输、物理接口定义 | RS-232, 100Base-T | 比特 |
2. 传输层协议
特性 | UDP | TCP |
---|---|---|
连接方式 | 无连接 | 面向连接(三次握手) |
可靠性 | 不保证送达 | 可靠传输(ACK+重传) |
数据边界 | 保留数据包边界 | 字节流(无边界) |
传输速度 | 更快(无连接开销) | 较慢(需维护连接状态) |
头部开销 | 8 字节 | 20-60 字节 |
适用场景 | 视频流、DNS、实时游戏、广播 | 文件传输、网页浏览 |
2.1 UDP
UDP(User Datagram Protocol)是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。
- 无连接传输
- 通信前无需建立连接,直接发送数据包
java.net.DatagramSocket
- 不可靠传输
- 不保证数据包顺序、不检测丢包、无重传机制
- 传输效率高于 TCP(头部仅 8 字节)
- 面向数据报
- 每次发送/接收都是完整数据包(有明确边界)
- 数据包最大长度: 64KB - 8 字节(头部)
- 支持广播/多播
- 可向同一网络内所有主机发送广播(地址:255.255.255.255)
- 支持多播(组播)地址范围:224.0.0.0 ~ 224.255.255.255
2.1.1 发送数据
import java.net.*;
public class UDPSender {
public static void main(String[] args) throws Exception {
// 1. 创建Socket(随机端口)
DatagramSocket socket = new DatagramSocket();
// 2. 准备数据包(目标地址为localhost,端口8888)
String message = "Hello UDP!";
byte[] data = message.getBytes();
InetAddress address = InetAddress.getByName("localhost");
DatagramPacket packet = new DatagramPacket(data, data.length, address, 8888);
// 3. 发送
socket.send(packet);
System.out.println("已发送: " + message);
// 4. 关闭
socket.close();
}
}
2.1.2 接收数据
import java.net.*;
public class UDPReceiver {
public static void main(String[] args) throws Exception {
// 1. 创建Socket并绑定端口8888
DatagramSocket socket = new DatagramSocket(8888);
// 2. 准备空数据包(缓冲区)
byte[] buffer = new byte[1024];
DatagramPacket packet = new DatagramPacket(buffer, buffer.length);
// 3. 阻塞接收
System.out.println("等待接收数据...");
socket.receive(packet); // 阻塞直到收到数据
// 4. 处理数据
String message = new String(packet.getData(), 0, packet.getLength());
System.out.println("收到来自" + packet.getAddress() + ":" + packet.getPort() + "的消息: " + message);
// 5. 关闭
socket.close();
}
}
2.1.3 广播
// 发送广播示例
socket.setBroadcast(true); // 开启广播
InetAddress broadcastAddress = InetAddress.getByName("255.255.255.255");
DatagramPacket broadcastPacket = new DatagramPacket(data, data.length, broadcastAddress, 8888);
socket.send(broadcastPacket);
2.1.4 多播(组播)
发送
// 加入多播组(224.0.0.0~224.255.255.255)
InetAddress group = InetAddress.getByName("224.0.0.1");
MulticastSocket multicastSocket = new MulticastSocket();
// 发送数据到组
DatagramPacket packet = new DatagramPacket(data, data.length, group, 8888);
multicastSocket.send(packet);
接收
MulticastSocket multicastSocket = new MulticastSocket(8888);
multicastSocket.joinGroup(InetAddress.getByName("224.0.0.1")); // 加入组
// 接收数据(同普通UDP接收)
multicastSocket.receive(packet);
2.2 TCP
TCP(Transmission Control Protocol)是一种面向连接的、可靠的、基于字节流的传输层通信协议。
- 面向连接:在数据传输之前,必须建立连接(三次握手),传输结束后要断开连接(四次挥手)。
- 可靠传输:通过确认机制、超时重传、流量控制、拥塞控制等机制保证数据正确到达。
- 字节流传输:数据被视为无结构的字节流,没有边界,但接收方收到的数据顺序与发送方发送的顺序一致。
2.2.1 三次握手
- 客户端发送 SYN(同步序列编号)包(SYN=1, seq=x)到服务器,进入 SYN_SENT 状态。
- 服务器收到 SYN 包,发送 SYN+ACK 包(SYN=1, ACK=1, seq=y, ack=x+1),进入 SYN_RECV 状态。
- 客户端收到 SYN+ACK 包,发送 ACK 包(ACK=1, seq=x+1, ack=y+1),进入 ESTABLISHED 状态。服务器收到 ACK 后也进入 ESTABLISHED 状态。
建立连接。
2.2.2 四次挥手
- 主动关闭方(假设为客户端)发送 FIN 包(FIN=1, seq=u),进入 FIN_WAIT_1 状态。
- 被动关闭方(服务器)收到 FIN,发送 ACK 包(ACK=1, seq=v, ack=u+1),进入 CLOSE_WAIT 状态。客户端收到 ACK 后进入 FIN_WAIT_2 状态。
- 服务器准备好关闭连接时,发送 FIN 包(FIN=1, seq=w, ack=u+1),进入 LAST_ACK 状态。
- 客户端收到 FIN,发送 ACK 包(ACK=1, seq=u+1, ack=w+1),进入 TIME_WAIT 状态,等待 2MSL(最大报文段生存时间)后关闭。服务器收到 ACK 后立即关闭。
断开连接。
2.2.3 实现
在 Java 中,我们可以使用 java.net.ServerSocket
和 java.net.Socket
类来实现 TCP 通信。
- 服务器端使用 ServerSocket 监听指定端口,等待客户端连接。当有客户端连接时,创建一个 Socket 对象,通过该对象进行通信。
- 客户端使用 Socket 连接到服务器,然后通过输出流向服务器发送数据,通过输入流读取服务器返回的数据。
服务器端
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
public class TCPServer {
public static void main(String[] args) throws IOException {
// 创建服务器Socket,监听8888端口
ServerSocket serverSocket = new ServerSocket(8888);
System.out.println("服务器启动,等待客户端连接...");
// 等待客户端连接
Socket socket = serverSocket.accept();
System.out.println("客户端连接成功!");
// 获取输入流,读取客户端数据
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String message = in.readLine();
System.out.println("收到客户端消息: " + message);
// 获取输出流,向客户端发送数据
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("你好,客户端!");
// 关闭资源
in.close();
out.close();
socket.close();
serverSocket.close();
}
}
客户端
import java.io.*;
import java.net.Socket;
public class TCPClient {
public static void main(String[] args) throws IOException {
// 创建客户端Socket,连接服务器
Socket socket = new Socket("localhost", 8888);
System.out.println("已连接到服务器...");
// 获取输出流,向服务器发送数据
PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
out.println("你好,服务器!");
// 获取输入流,读取服务器返回的数据
BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
String response = in.readLine();
System.out.println("收到服务器响应: " + response);
// 关闭资源
out.close();
in.close();
socket.close();
}
}
3. 应用层协议
特性 | HTTP | HTTPS(HTTP+SSL/TLS) |
---|---|---|
安全性 | 明文传输(易被窃听) | 加密传输(防窃听/篡改) |
默认端口 | 80 | 443 |
性能 | 较高(无加密开销) | 较低(加密/解密消耗 CPU) |
证书 | 不需要 | 需要 CA 颁发的数字证书 |
适用场景 | 非敏感信息传输(如新闻网站) | 敏感信息传输(如支付/登录) |
3.1 HTTP
HTTP(HyperText Transfer Protocol)是应用层协议,基于 TCP/IP 协议族,用于在 Web 浏览器和服务器之间传输超文本(如 HTML)。
在 Java 中,我们可以使用 HttpURLConnection
或第三方库如 Apache HttpClient 来演示 HTTP 通信。
应用层协议
- 基于 TCP/IP 协议栈,用于 Web 浏览器和服务器之间的通信
- 默认端口:HTTP(80)/HTTPS(443)
- 遵循请求-响应模型:客户端发起请求,服务器返回响应
无状态协议
- 每个请求相互独立,服务器不保留客户端状态
- 通过 Cookie/Session 机制实现状态管理
报文结构
请求报文
GET /index.html HTTP/1.1 Host: www.example.com User-Agent: Java-HTTP-Client
响应报文
HTTP/1.1 200 OK Content-Type: text/html Content-Length: 1024 <!DOCTYPE html>...
3.1.1 URL 结构
标准格式:协议://主机[:端口]/路径?查询字符串#片段标识符
示例:http://example.com:8080/api/data?category=books#section2
3.1.2 HTTP 方法
方法 | 作用 |
---|---|
GET | 获取资源 |
POST | 提交数据 |
PUT | 更新资源 |
DELETE | 删除资源 |
HEAD | 获取响应头(无响应体) |
3.1.3 状态码
状态码 | 类别 | 说明 |
---|---|---|
1xx | 信息响应 | 请求已被接收 |
2xx | 成功 | 请求处理成功 |
3xx | 重定向 | 需进一步操作 |
4xx | 客户端错误 | 请求包含错误语法 |
5xx | 服务器错误 | 服务器处理请求失败 |
3.1.4 发展
- HTTP/1.0:每个请求需单独建立连接
- HTTP/1.1:默认持久连接(可复用 TCP 连接)
- HTTP/2:二进制分帧、头部压缩、多路复用
- HTTP/3:基于 QUIC 协议(UDP 实现),解决队头阻塞
3.1.5 GET 请求
import java.net.HttpURLConnection;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class HttpClientExample {
public static void main(String[] args) throws Exception {
URL url = new URL("http://example.com/api/data");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法
connection.setRequestMethod("GET");
// 添加请求头
connection.setRequestProperty("User-Agent", "Java HTTP Client");
// 获取响应码
int status = connection.getResponseCode();
System.out.println("响应状态码: " + status);
// 读取响应体
try (BufferedReader reader = new BufferedReader(
new InputStreamReader(connection.getInputStream()))) {
String line;
StringBuilder response = new StringBuilder();
while ((line = reader.readLine()) != null) {
response.append(line);
}
System.out.println("响应内容: " + response.toString());
}
// 断开连接
connection.disconnect();
}
}
3.1.6 POST 请求
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
public class HttpPostExample {
public static void main(String[] args) throws Exception {
URL url = new URL("http://example.com/api/users");
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
// 设置请求方法
connection.setRequestMethod("POST");
connection.setDoOutput(true); // 允许输出
// 设置请求头(JSON类型)
connection.setRequestProperty("Content-Type", "application/json");
// 准备JSON数据
String jsonInput = "{\"name\": \"Alice\", \"age\": 30}";
// 发送请求体
try (OutputStream os = connection.getOutputStream()) {
byte[] input = jsonInput.getBytes("utf-8");
os.write(input, 0, input.length);
}
// 处理响应,同GET请求
int status = connection.getResponseCode();
}
}
3.1.7 超时
connection.setConnectTimeout(5000); // 5秒连接超时
connection.setReadTimeout(10000); // 10秒读取超时
3.1.8 重定向
// 自动跟随重定向(默认true)
connection.setInstanceFollowRedirects(true);
// 手动处理重定向
if (status == HttpURLConnection.HTTP_MOVED_PERM) {
String newUrl = connection.getHeaderField("Location");
// 重新发起请求...
}
3.2 HTTPS
// 创建HTTPS连接
URL url = new URL("https://example.com");
HttpsURLConnection httpsConn = (HttpsURLConnection) url.openConnection();
// 配置SSL证书验证(生产环境需使用真实CA证书)
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) {}
public void checkServerTrusted(X509Certificate[] chain, String authType) {}
public X509Certificate[] getAcceptedIssuers() { return new X509Certificate[0]; }
}}, new SecureRandom());
httpsConn.setSSLSocketFactory(sslContext.getSocketFactory());
httpsConn.setHostnameVerifier((hostname, session) -> true); // 跳过主机名验证
// 后续操作与HTTP相同
3.3 WebSocket
WebSocket 是一种在单个 TCP 连接上进行全双工通信的协议,它允许服务端主动向客户端推送数据,非常适合实时应用。
特性 | HTTP | WebSocket |
---|---|---|
通信模式 | 半双工(请求-响应) | 全双工(双向通信) |
连接建立 | 每次请求都需要建立连接 | 一次握手,持久连接 |
头部开销 | 每次请求携带完整 HTTP 头(~800B) | 初始握手后,数据帧头仅 2~14 字节 |
实时性 | 依赖轮询(高延迟) | 实时推送(低延迟) |
适用场景 | 传统网页浏览 | 实时聊天、股票行情、游戏 |
- 全双工实时通信
- 基于 TCP 的持久化连接协议(与 HTTP 互补)
- 服务端和客户端可同时双向传输数据(突破 HTTP 请求-响应限制)
- 默认端口:WS(80)/WSS(443),与 HTTP/HTTPS 端口一致
- 低开销高效传输
- 连接建立后,数据帧头部仅 2-14 字节(远小于 HTTP 头部)
- 避免 HTTP 轮询的资源浪费,适合实时应用(聊天、游戏等)
- 协议升级机制
- 通过 HTTP 升级握手建立连接:
GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
- 通过 HTTP 升级握手建立连接:
3.3.1 服务端实现
使用 JSR 356 标准 API。
import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;
@ServerEndpoint("/chat") // 声明 WebSocket 端点路径
public class ChatEndpoint {
@OnOpen
public void onOpen(Session session) {
System.out.println("客户端连接: " + session.getId());
}
@OnMessage
public void onMessage(String message, Session session) {
System.out.println("收到消息: " + message);
// 广播消息给所有客户端
session.getOpenSessions().forEach(s -> {
try {
s.getBasicRemote().sendText("Echo: " + message);
} catch (Exception e) { e.printStackTrace(); }
});
}
@OnClose
public void onClose(Session session) {
System.out.println("连接关闭: " + session.getId());
}
@OnError
public void onError(Session session, Throwable error) {
error.printStackTrace();
}
}
3.3.2 客户端实现
import javax.websocket.*;
import java.net.URI;
@ClientEndpoint
public class WebSocketClient {
@OnOpen
public void onOpen(Session session) {
System.out.println("连接服务器成功");
try {
session.getBasicRemote().sendText("Hello Server!");
} catch (Exception e) { e.printStackTrace(); }
}
@OnMessage
public void onMessage(String message) {
System.out.println("收到服务端消息: " + message);
}
public static void main(String[] args) throws Exception {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(WebSocketClient.class,
new URI("ws://localhost:8080/chat")); // WebSocket 地址
}
}
3.3.3 二进制数据传输
@OnMessage
public void onMessage(ByteBuffer data, Session session) {
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
System.out.println("收到二进制数据长度: " + bytes.length);
}
// 发送二进制数据
session.getBasicRemote().sendBinary(ByteBuffer.wrap(new byte[]{0x48,0x65,0x6C,0x6C,0x6F}));
3.3.4 连接管理
// 获取所有活动会话
Set<Session> sessions = session.getOpenSessions();
// 异步发送(避免阻塞)
session.getAsyncRemote().sendText("异步消息");
3.3.5 安全连接 (WSS)
// 客户端连接使用 wss 协议
new URI("wss://example.com/chat");
// 服务端配置 SSL(Tomcat 示例)
<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
SSLEnabled="true" scheme="https" secure="true">
<SSLHostConfig certificateVerification="none"/>
</Connector>
4. HTTP 报文
4.1 请求报文
纯文本格式传输。分为三个部分:请求行(Request Line)、请求头(Request Headers)、空行(CRLF)、请求体(Request Body)。
POST /login HTTP/1.1 -- 请求行
Host: www.example.com -- 请求头
Content-Type: application/x-www-form-urlencoded
Content-Length: 27
User-Agent: Mozilla/5.0
-- 空行
username=admin&password=123 -- 请求体
4.1.1 请求行(Request Line)
请求行是报文的第一行,包含三个关键元素,以空格分隔。
- 请求方法(Request Method):指定操作类型,如 GET(获取资源)、POST(提交数据)、PUT(更新资源)或 DELETE(删除资源)。
- 请求 URI(Request URI):标识目标资源路径,例如/index.html 或完整 URL 路径。
- 协议版本(Protocol Version):指定 HTTP 版本,如 HTTP/1.1 或 HTTP/2。
例如 GET /api/data HTTP/1.1:
- GET: 请求方法
- /api/data: 请求 URI
- HTTP/1.1: 协议版本
4.1.2 请求头(Request Headers)
请求头从第二行开始,到第一个空行为止。
- Host: www.example.com:指定服务器域名(HTTP/1.1必需)。
- User-Agent: Mozilla/5.0:标识客户端类型。
- Content-Type: application/json:定义请求体的媒体类型。
- Authorization: Bearer token:用于认证。
4.1.3 请求体(Request Body)
请求体在空行之后。
主要用于 POST、PUT 等方法,提交表单、JSON 或文件。
- 什么内容由 Content-Type 决定
- application/x-www-form-urlencoded:表单数据(如 username=admin&password=123)。
- application/json:JSON 数据(如{“name”: “John”})。
- multipart/form-data:文件上传。
4.2 响应报文
响应报文结构通常包括:状态行(Status Line)、响应头(Response Headers)、空行(CRLF)、响应体(Response Body)。
HTTP/1.1 200 OK -- 状态行
Content-Type: text/html; charset=UTF-8 -- 响应头
Content-Length: 1223
Last-Modified: Wed, 21 Oct 2015 14:26:38 GMT
-- 空行
<html> -- 响应体
<body>
<h1>Hello, world!</h1>
</body>
</html>
4.2.1 状态行(Status Line)
位于报文首行。
- 协议版本:HTTP/1.1
- 定义 HTTP 协议版本(HTTP/1.0、HTTP/1.1、HTTP/2 等)
- 状态码: 200
- 三位数字代码,表示请求处理结果:
- 1xx:信息类(如 101 Switching Protocols)
- 2xx:成功(如 200 OK,201 Created)
- 3xx:重定向(如 301 Moved Permanently)
- 4xx:客户端错误(如 404 Not Found)
- 5xx:服务端错误(如 500 Internal Server Error)
- 原因短语:OK
- 状态码的文本描述(可自定义但通常遵循标准)
4.2.2 响应头(Response Headers)
键值对集合,每个头占一行,描述服务器信息和响应属性。
- Content-Type : 响应体数据类型(必需)
- text/html; charset=UTF-8
- Content-Length : 响应体字节数(精确匹配实际长度)
- 1223
- Last-Modified : 资源最后修改时间(用于缓存验证)
- Wed, 21 Oct 2015 14:26:38 GMT
- Cache-Control : 缓存控制指令
- max-age=3600, public
- Set-Cookie : 服务器设置客户端 Cookie
- sessionId=abc123; Path=/; Secure
- Location : 重定向目标 URL(配合 3xx 状态码)
- https://newdomain.com/resource
- Server : 服务器软件信息
- Nginx/1.18.0
- ETag : 资源版本标识符(用于缓存验证)
- “33a64df551425fcc55e4d42a148795d9”
4.2.3 响应体(Response Body)
包含实际返回的资源数据,格式由 Content-Type 决定:
- 文本类型:HTML、CSS、JSON 等可直接阅读
- 二进制类型:如图片(image/jpeg)、压缩文件(application/zip)等
4.2.4 性能优化
- 启用压缩:Content-Encoding: gzip
- 缓存控制:Cache-Control: public, max-age=31536000
4.2.5 安全规范
- 敏感 Cookie 需加 Secure; HttpOnly 属性
- 跨域资源需设置 Access-Control-Allow-Origin
5. HTTP 请求头
5.1 通用请求头(General Headers)
适用于所有请求类型的头部。
- Cache-Control
控制缓存行为:no-cache(禁用缓存)、max-age=3600(缓存有效期) - Connection
控制连接状态:keep-alive(保持连接)、close(关闭连接) - Upgrade
请求协议升级:Upgrade: websocket(升级到 WebSocket 协议) - Via
显示请求经过的代理路径:Via: 1.1 proxy1, 1.1 proxy2
5.2 实体头(Entity Headers)
描述请求体内容的头部。
- Content-Length
请求体字节数:Content-Length: 348(精确长度必须匹配) - Content-Type 请求体数据类型:
application/json(JSON 数据)
multipart/form-data(文件上传)
application/x-www-form-urlencoded(表单数据) - Content-Encoding
请求体压缩格式:gzip、deflate、br - Content-Language
请求体语言:zh-CN、en-US
5.3 请求控制头(Request Control Headers)
控制请求处理逻辑的头部。
- Host(必需)
目标服务器域名:Host: www.example.com(HTTP/1.1强制要求) - User-Agent
客户端标识:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36
- Referer
请求来源 URL:Referer: https://www.google.com/(用于流量分析)
5.4 内容协商头(Content Negotiation)
客户端声明可接受的内容类型。
- Accept
响应内容类型偏好:Accept: text/html, application/xhtml+xml;q=0.9(q 值表示权重) - Accept-Encoding
可接受的压缩格式:gzip, deflate, br - Accept-Language
语言偏好:Accept-Language: zh-CN, en-US;q=0.7 - Accept-Charset
字符集偏好:Accept-Charset: utf-8, iso-8859-1(现代浏览器通常忽略)
5.5 认证头(Authentication Headers)
身份验证相关头部。
- Authorization
身份凭证:- Basic dXNlcjpwYXNz(Base64 编码)
- Bearer eyJhbGci…(JWT 令牌)
- Proxy-Authorization
代理服务器认证:Proxy-Authorization: Basic YWxhZGRpbjp…
5.6 条件请求头(Conditional Headers)
基于资源状态的条件请求。
- If-Match
ETag 匹配检查:If-Match: “737060cd8c284d8af7ad3082f209582d” - If-None-Match
ETag 不匹配时请求:用于缓存验证(返回 304 Not Modified)4 - If-Modified-Since
时间戳检查:If-Modified-Since: Wed, 21 Oct 2025 07:28:00 GMT - If-Unmodified-Since
资源未修改时操作:用于并发控制
5.7 特殊用途头(Special Purpose Headers)
特定场景使用的头部。
- Range
请求部分内容:Range: bytes=0-499(断点续传) - Origin
跨域请求来源:Origin: https://www.domain.com(CORS必需) - Cookie
客户端存储数据:Cookie: sessionId=38afes7a8; userId=john - DNT (Do Not Track)
隐私请求:DNT: 1(请求不跟踪用户行为)
6. HTTP 响应头
6.1 基础控制头
- Content-Type
指定响应体的媒体类型(MIME 类型)和字符编码,例如:Content-Type: text/html; charset=utf-8
表示返回 HTML 文档,使用 UTF-8 编码。 - Content-Length
声明响应体的字节长度,例如:Content-Length: 1024
表示响应体大小为 1KB。 - Transfer-Encoding
指定传输编码方式,常见值:- chunked:响应体分块传输(动态内容常用)
- gzip:响应体压缩传输。
6.2 缓存控制头
- Cache-Control
控制缓存行为,常用指令:- no-cache:强制向服务器验证缓存
- max-age=3600:资源有效期 1 小时
- public:允许中间代理缓存。
- Expires
设定资源过期时间(GMT 格式),例如:Expires: Wed, 21 Oct 2025 07:28:00 GMT
。 - ETag
资源版本标识符(如文件哈希值),用于缓存验证:ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
。
6.3 重定向与刷新头
Location
配合 3xx 状态码实现重定向,指定新 URL:Location: https://example.com/new-page
。Refresh
设置页面自动刷新/跳转:Refresh: 5; url=https://example.com
表示 5 秒后跳转到指定 URL。
6.4 安全控制头
Content-Security-Policy (CSP)
定义内容安全策略,防止 XSS 攻击:Content-Security-Policy: default-src 'self'
表示仅允许加载同源资源。Strict-Transport-Security (HSTS)
强制 HTTPS 连接:Strict-Transport-Security: max-age=31536000
表示 1 年内自动转 HTTPS。
6.5 特殊功能头
- Content-Disposition
控制文件下载行为:Content-Disposition: attachment; filename="report.pdf"
触发文件下载并指定文件名。 - Set-Cookie
服务器向客户端设置 Cookie:Set-Cookie: sessionid=38afes7a8; HttpOnly; Secure HttpOnly
禁止 JS 访问,Secure 仅限 HTTPS 传输。 - Access-Control-Allow-Origin
跨域资源共享(CORS)关键头:Access-Control-Allow-Origin: *
允许所有域访问资源。
6.6 服务器信息头
- Server
暴露服务器类型和版本:Server: nginx/1.18.0
(建议隐藏以减少攻击面)。 - X-Powered-By
显示后端技术栈(如 PHP 版本):X-Powered-By: PHP/7.4.3
。
7. Cookie, Session
- Cookie:客户端存储机制(≤4KB),通过 Set-Cookie 头创建
- Session:服务器端存储机制,通过 Session ID 标识客户端
- 区别:
- Cookie 数据存储在浏览器,Session 数据存储在服务器
- Cookie 可长期保存,Session 随会话结束失效
- Cookie 有 4KB 限制,Session 无硬性限制
8. JWT
JWT(JSON Web Token)是目前最流行的跨域认证解决方案,特别适用于分布式站点的单点登录(SSO)场景。
JWT的最大优势是服务器不再需要存储Session状态,使得服务器认证鉴权业务可以方便扩展。
特性 | Session 机制 | JWT(JSON Web Token) |
---|---|---|
存储位置 | 服务器端(内存/数据库) | 客户端(localStorage/Cookie) |
数据结构 | 会话 ID(无状态标识) | 自包含 JSON(Header.Payload.Signature) |
通信方式 | 通过 Cookie 传递 Session ID | 通过 HTTP Header 或 URL 参数传递 |
状态管理 | 有状态(服务器存储会话数据) | 无状态(所有信息在 Token 中) |
扩展性 | 集群部署需 Session 共享方案 | 天然支持分布式系统 |
- 如果Token存储在localStorage中,可能面临XSS攻击的风险(因为JavaScript可以读取)。如果存储在HttpOnly的Cookie中,则相对安全,但也要注意CSRF。
- JWT的Token体积通常比Session ID大,每次请求都会在HTTP头部中携带,增加带宽消耗。
- 一旦签发,在有效期内无法撤销。
- Token中可以直接存储用户信息(如用户ID、角色等),服务器解析Token即可获取,无需额外查询。
8.1 前端实现
8.1.1 登录获取 JWT
登录获取JWT并存进Cookie中。
async function login() {
const res = await fetch('http://localhost:8080/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
username: 'admin',
password: 'password123'
}),
credentials: 'include' // 必须包含凭据
});
if (res.ok) alert('登录成功!Cookie已设置');
}
8.1.2 访问受保护资源
自动携带Cookie中的JWT发送请求。
async function fetchData() {
const res = await fetch('/protected', {
credentials: 'include' // 自动发送Cookie
});
if (res.ok) {
const data = await res.text();
alert('获取数据: ' + data);
} else {
alert('访问失败: ' + res.status);
}
}
8.2 后端实现
需要添加jsonwebtoken包,以SpringBoot进行演示。
8.2.1 登录接口
后端签发设置HttpOnly、Secure和SameSite属性以增强安全性(如防止XSS和CSRF攻击)。
@RestController
public class AuthController {
@PostMapping("/login")
public ResponseEntity<String> login(
@RequestBody LoginRequest request,
HttpServletResponse response) {
// 1. 验证用户名密码
if ("admin".equals(request.username()) && "password123".equals(request.password())) {
// 2. 生成JWT
String jwt = JwtUtil.generateToken(request.username());
// 3. 创建安全Cookie
Cookie cookie = new Cookie("jwt", jwt);
cookie.setHttpOnly(true); // 防止XSS攻击
cookie.setSecure(true); // 仅HTTPS传输
cookie.setPath("/"); // 全局路径
cookie.setMaxAge(3600); // 1小时有效期
cookie.setAttribute("SameSite", "Strict"); // 防止CSRF
// 4. 添加到响应头
response.addCookie(cookie);
return ResponseEntity.ok("登录成功");
}
return ResponseEntity.status(401).body("认证失败");
}
}
8.2.2 受保护资源接口
@GetMapping("/protected")
public ResponseEntity<String> protectedResource(
@CookieValue("jwt") String token) { // 自动从Cookie提取
if (JwtUtil.validateToken(token)) {
return ResponseEntity.ok("访问成功!这是受保护资源");
}
return ResponseEntity.status(401).body("无效令牌");
}
8.2.3 JwtUtil
public class JwtUtil {
// 生成带IP绑定的JWT
public static String generateToken(String username, String ip) {
return Jwts.builder()
.setSubject(username)
.claim("ip", ip) // 绑定客户端IP
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(Keys.hmacShaKeyFor(SECRET.getBytes()))
.compact();
}
// 验证时检查IP
public static boolean validateToken(String token, String clientIp) {
Claims claims = Jwts.parserBuilder()
.setSigningKey(SECRET.getBytes())
.build()
.parseClaimsJws(token)
.getBody();
return claims.get("ip").equals(clientIp);
}
}
8.2.4 CORS配置
@Configuration
public class CorsConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://yourdomain.com")
.allowedMethods("*")
.allowCredentials(true); // 必须允许凭据
}
}