当前位置: 首页 > news >正文

Java网络编程(UDP, TCP, HTTP)

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. 传输层协议

特性UDPTCP
连接方式无连接面向连接(三次握手)
可靠性不保证送达可靠传输(ACK+重传)
数据边界保留数据包边界字节流(无边界)
传输速度更快(无连接开销)较慢(需维护连接状态)
头部开销8 字节20-60 字节
适用场景视频流、DNS、实时游戏、广播文件传输、网页浏览

2.1 UDP

UDP(User Datagram Protocol)是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务。

  1. 无连接传输
    • 通信前无需建立连接,直接发送数据包
    • java.net.DatagramSocket
  2. 不可靠传输
    • 不保证数据包顺序、不检测丢包、无重传机制
    • 传输效率高于 TCP(头部仅 8 字节)
  3. 面向数据报
    • 每次发送/接收都是完整数据包(有明确边界)
    • 数据包最大长度: 64KB - 8 字节(头部)
  4. 支持广播/多播
    • 可向同一网络内所有主机发送广播(地址: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并绑定端口8888DatagramSocket 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)是一种面向连接的、可靠的、基于字节流的传输层通信协议。

  1. 面向连接:在数据传输之前,必须建立连接(三次握手),传输结束后要断开连接(四次挥手)。
  2. 可靠传输:通过确认机制、超时重传、流量控制、拥塞控制等机制保证数据正确到达。
  3. 字节流传输:数据被视为无结构的字节流,没有边界,但接收方收到的数据顺序与发送方发送的顺序一致。

2.2.1 三次握手

  1. 客户端发送 SYN(同步序列编号)包(SYN=1, seq=x)到服务器,进入 SYN_SENT 状态。
  2. 服务器收到 SYN 包,发送 SYN+ACK 包(SYN=1, ACK=1, seq=y, ack=x+1),进入 SYN_RECV 状态。
  3. 客户端收到 SYN+ACK 包,发送 ACK 包(ACK=1, seq=x+1, ack=y+1),进入 ESTABLISHED 状态。服务器收到 ACK 后也进入 ESTABLISHED 状态。

建立连接。

2.2.2 四次挥手

  1. 主动关闭方(假设为客户端)发送 FIN 包(FIN=1, seq=u),进入 FIN_WAIT_1 状态。
  2. 被动关闭方(服务器)收到 FIN,发送 ACK 包(ACK=1, seq=v, ack=u+1),进入 CLOSE_WAIT 状态。客户端收到 ACK 后进入 FIN_WAIT_2 状态。
  3. 服务器准备好关闭连接时,发送 FIN 包(FIN=1, seq=w, ack=u+1),进入 LAST_ACK 状态。
  4. 客户端收到 FIN,发送 ACK 包(ACK=1, seq=u+1, ack=w+1),进入 TIME_WAIT 状态,等待 2MSL(最大报文段生存时间)后关闭。服务器收到 ACK 后立即关闭。

断开连接。

2.2.3 实现

在 Java 中,我们可以使用 java.net.ServerSocketjava.net.Socket 类来实现 TCP 通信。

  1. 服务器端使用 ServerSocket 监听指定端口,等待客户端连接。当有客户端连接时,创建一个 Socket 对象,通过该对象进行通信。
  2. 客户端使用 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. 应用层协议

特性HTTPHTTPS(HTTP+SSL/TLS)
安全性明文传输(易被窃听)加密传输(防窃听/篡改)
默认端口80443
性能较高(无加密开销)较低(加密/解密消耗 CPU)
证书不需要需要 CA 颁发的数字证书
适用场景非敏感信息传输(如新闻网站)敏感信息传输(如支付/登录)

3.1 HTTP

HTTP(HyperText Transfer Protocol)是应用层协议,基于 TCP/IP 协议族,用于在 Web 浏览器和服务器之间传输超文本(如 HTML)。
在 Java 中,我们可以使用 HttpURLConnection 或第三方库如 Apache HttpClient 来演示 HTTP 通信。

  1. 应用层协议

    1. 基于 TCP/IP 协议栈,用于 Web 浏览器和服务器之间的通信
    2. 默认端口:HTTP(80)/HTTPS(443)
    3. 遵循请求-响应模型:客户端发起请求,服务器返回响应
  2. 无状态协议

    1. 每个请求相互独立,服务器不保留客户端状态
    2. 通过 Cookie/Session 机制实现状态管理
  3. 报文结构

    1. 请求报文

      GET /index.html HTTP/1.1
      Host: www.example.com
      User-Agent: Java-HTTP-Client
      
    2. 响应报文

      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 发展

  1. HTTP/1.0:每个请求需单独建立连接
  2. HTTP/1.1:默认持久连接(可复用 TCP 连接)
  3. HTTP/2:二进制分帧、头部压缩、多路复用
  4. 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 连接上进行全双工通信的协议,它允许服务端主动向客户端推送数据,非常适合实时应用。

特性HTTPWebSocket
通信模式半双工(请求-响应)全双工(双向通信)
连接建立每次请求都需要建立连接一次握手,持久连接
头部开销每次请求携带完整 HTTP 头(~800B)初始握手后,数据帧头仅 2~14 字节
实时性依赖轮询(高延迟)实时推送(低延迟)
适用场景传统网页浏览实时聊天、股票行情、游戏
  1. 全双工实时通信
    1. 基于 TCP 的持久化连接协议(与 HTTP 互补)
    2. 服务端和客户端可同时双向传输数据(突破 HTTP 请求-响应限制)
    3. 默认端口:WS(80)/WSS(443),与 HTTP/HTTPS 端口一致
  2. 低开销高效传输
    1. 连接建立后,数据帧头部仅 2-14 字节(远小于 HTTP 头部)
    2. 避免 HTTP 轮询的资源浪费,适合实时应用(聊天、游戏等)
  3. 协议升级机制
    1. 通过 HTTP 升级握手建立连接:
      GET /chat HTTP/1.1
      Host: example.com
      Upgrade: websocket
      Connection: Upgrade
      Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
      Sec-WebSocket-Version: 13
      

3.3.1 服务端实现

使用 JSR 356 标准 API。

import javax.websocket.*;
import javax.websocket.server.ServerEndpoint;@ServerEndpoint("/chat") // 声明 WebSocket 端点路径
public class ChatEndpoint {@OnOpenpublic void onOpen(Session session) {System.out.println("客户端连接: " + session.getId());}@OnMessagepublic 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(); }});}@OnClosepublic void onClose(Session session) {System.out.println("连接关闭: " + session.getId());}@OnErrorpublic void onError(Session session, Throwable error) {error.printStackTrace();}
}

3.3.2 客户端实现

import javax.websocket.*;
import java.net.URI;@ClientEndpoint
public class WebSocketClient {@OnOpenpublic void onOpen(Session session) {System.out.println("连接服务器成功");try {session.getBasicRemote().sendText("Hello Server!");} catch (Exception e) { e.printStackTrace(); }}@OnMessagepublic 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)

请求行是报文的第一行,包含三个关键元素,以空格分隔。

  1. 请求方法(Request Method):指定操作类型,如 GET(获取资源)、POST(提交数据)、PUT(更新资源)或 DELETE(删除资源)。
  2. 请求 URI(Request URI):标识目标资源路径,例如/index.html 或完整 URL 路径。
  3. 协议版本(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)

位于报文首行。

  1. 协议版本:HTTP/1.1
    1. 定义 HTTP 协议版本(HTTP/1.0、HTTP/1.1、HTTP/2 等)
    2. 状态码: 200
  2. 三位数字代码,表示请求处理结果:
    1. 1xx:信息类(如 101 Switching Protocols)
    2. 2xx:成功(如 200 OK,201 Created)
    3. 3xx:重定向(如 301 Moved Permanently)
    4. 4xx:客户端错误(如 404 Not Found)
    5. 5xx:服务端错误(如 500 Internal Server Error)
  3. 原因短语:OK
    1. 状态码的文本描述(可自定义但通常遵循标准)

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 性能优化

  1. 启用压缩:Content-Encoding: gzip
  2. 缓存控制:Cache-Control: public, max-age=31536000

4.2.5 安全规范

  1. 敏感 Cookie 需加 Secure; HttpOnly 属性
  2. 跨域资源需设置 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

  1. Cookie:客户端存储机制(≤4KB),通过 Set-Cookie 头创建
  2. Session:服务器端存储机制,通过 Session ID 标识客户端
  3. 区别:
    • 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 共享方案天然支持分布式系统
  1. 如果Token存储在localStorage中,可能面临XSS攻击的风险(因为JavaScript可以读取)。如果存储在HttpOnly的Cookie中,则相对安全,但也要注意CSRF。
  2. JWT的Token体积通常比Session ID大,每次请求都会在HTTP头部中携带,增加带宽消耗。
  3. 一旦签发,在有效期内无法撤销。
  4. 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. 生成JWTString jwt = JwtUtil.generateToken(request.username());// 3. 创建安全CookieCookie 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绑定的JWTpublic 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();}// 验证时检查IPpublic 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 {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedOrigins("https://yourdomain.com").allowedMethods("*").allowCredentials(true); // 必须允许凭据}
}
http://www.dtcms.com/a/354591.html

相关文章:

  • 【Linux基础知识系列:第一百一十五篇】使用gzip与bzip2进行压缩
  • 从首次测试到采购40个机器人:Junior kühlk如何自动化协作机械臂矩阵
  • Linux学习-基于TCP实现群聊
  • 医疗AI时代的生物医学Go编程:高性能计算与精准医疗的案例分析(三)
  • windows下查看别的服务器的端口是否通
  • [光学原理与应用-319]:激光器光路设计的主要输出文件的形式和内容
  • 解构与重构:“真人不露相,露相非真人” 的存在论新解 —— 论 “真在” 的行为表达本质
  • 一文读懂:用PyTorch从零搭建一个Transformer模型
  • (LeetCode 每日一题) 3446. 按对角线进行矩阵排序(矩阵、排序)
  • 读大语言模型08计算基础设施
  • GeoScene Maps 完整入门指南:从安装到实战
  • 《Explanation of Adaptive Platform Design》详细解读
  • 同一个栅格数据,为何在QGIS和ArcGIS Pro中打开后显示的数值范围不同?
  • redis单哨兵模式
  • 单元测试到底是什么?该怎么做?
  • 破译心智密码:神经科学如何为下一代自然语言处理绘制语义理解的蓝图
  • 【后端】微服务后端鉴权方案
  • 总结:在工作场景中的应用。(Excel)
  • UGUI源码剖析(13):交互的基石——Selectable状态机与Button事件
  • 【qml-7】qml与c++交互(自动补全提示)
  • mac m4执行nvm install 14.19.1报错,安装低版本node报错解决
  • 微服务保护和分布式事务-01.雪崩问题-原因分析
  • LeetCode-279. 完全平方数
  • 楼宇自控系统应需而生为现代建筑装上智能化翅膀
  • 【论文阅读】CLIP: 从自然语言监督中学习可迁移的视觉模型
  • 移动端网页调试实战,iOS WebKit Debug Proxy 的应用与替代方案
  • 《口令猜测研究进展》——论文阅读
  • springboot连接不上redis,但是redis客户端是能连接上的
  • ⸢ 贰 ⸥ ⤳ 安全架构:数字银行安全体系规划
  • iOS混淆工具实战,社交类 App 的隐私与安全防护混淆流程