http
Http 是互联网应用最广泛的客户端-服务器通信协议,用于规范浏览器、移动应用等客户端与 Web 服务器之间的数据交互。
HTTP 的特点
- 无状态协议:服务器不会记忆客户端的历史请求,每次请求都是独立的
- 只能由客户端发起请求,服务器接收后返回响应请求,服务器不会主动向客户端发送数据
- 通过请求方法、状态码(200、403、404 等等)、头部字段(数据信息、请求头等等)实现
- 标准 HTTP 在传输层使用 TCP,但数据以明文形式发送,有被监听、窃取的风险;HTTPS 通过加密保护数据安全
工作流程
- 建立 TCP 连接,客户端通过 TCP 协议与服务器的端口建立连接(三次握手)
- 客户端发起 HTTP 请求,客户端向服务器发送请求报文,包含要访问的 u 资源和客户端信息
- 服务器解析请求报文,处理业务逻辑
- 服务器将处理结果封装为响应报文,返回给客户端
- 客户端解析响应报文,处理数据
- 关闭 TCP 连接
HTTP 请求报文结构
请求报文由请求行、请求头、空行、请求体四部分组成,格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| GET /index.html HTTP/1.1
Host: example.com User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/114.0.0.0 Safari/537.36 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*
|
HTTP 响应报文结构
响应报文由状态行、响应头、空行、响应体四部分组成,格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| HTTP/1.1 200 OK
Server: Nginx Date: Wed, 15 Aug 2025 12:00:00 GMT Content-Type: text/html; charset=utf-8 Content-Length: 1024 Set-Cookie: sessionId=abc123; HttpOnly; Max-Age=3600 Connection: keep-alive
(空行)
<!DOCTYPE html> <html> <head><title>示例页面</title></head> <body>Hello World</body> </html>
|
WebSocket
WebSocket 是一种全双工通信协议,它实现了客户端与服务器之间的持久连接和双向实时通信,服务器可以主动向客户端发送请求,彻底改变了传统 HTTP 协议 “请求 - 响应” 模式的局限性
HTTP 通信方向单一,只能由客户端发起请求,服务器无法主动向客户端推送数据,并且每次请求完成后需要关闭连接,频繁通信会产生大量握手开销。
Websocket 中客户端和服务器可同时向对方发送数据,一次握手建立连接后,保持长期活跃,避免重复连接开销;无需 HTTP 多次握手,数据传输更高效
工作流程
Websocket 独立于 HTTP 的协议,但是借助了 HTTP 完成握手,之后完全脱离 HTTP 进行通信
- 建立连接:客户端向服务器发送一个特殊的 HTTP 请求,声明要升级到 WebSocket 协议,请求头包含:
1 2 3 4 5 6
| GET /chat HTTP/1.1 Host: example.com Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== Sec-WebSocket-Version: 13
|
- 服务器响应握手确认:服务器同一升级后,返回 HTTP 101 状态码(协议切换),并在响应头中验证客户端的请求,验证成功后,HTTP 升级为 WebSocket,后续通信不在使用 HTTP 协议。
1 2 3 4
| HTTP/1.1 101 Switching Protocols Upgrade: websocket Connection: Upgrade Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
|
- 双向通信:建立连接后,客户端和服务器可随时向对方发送数据,数据格式为二进制帧或文本帧(通常为 JSON 格式传输结构化数据)
- 任何一方可发送关闭帧主动断开连接,另一方确认后完成关闭
使用
客户端:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| const ws = new WebSocket("wss://example.com/chat");
ws.onopen = () => { console.log("WebSocket 连接已建立"); ws.send(JSON.stringify({ type: "join", username: "张三" })); };
ws.onmessage = (event) => { const data = JSON.parse(event.data); console.log("收到消息:", data); };
ws.onclose = (event) => { console.log("连接已关闭,代码:", event.code, "原因:", event.reason); };
ws.onerror = (error) => { console.error("连接错误:", error); };
|
服务器(Spring Boot):
- 引入 websocket 依赖
1 2 3 4 5 6 7 8 9 10 11
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
|
- 创建配置类
1 2 3 4 5 6 7 8 9 10 11 12
| import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.socket.server.standard.ServerEndpointExporter;
@Configuration public class WebSocketConfig { @Bean public ServerEndpointExporter serverEndpointExporter() { return new ServerEndpointExporter(); } }
|
- 业务实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95
| import org.springframework.stereotype.Component; import javax.websocket.*; import javax.websocket.server.PathParam; import javax.websocket.server.ServerEndpoint; import java.io.IOException; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArraySet;
@ServerEndpoint("/ws/{username}") @Component public class WebSocketServer { private static int onlineCount = 0;
private static ConcurrentHashMap<String, WebSocketServer> clients = new ConcurrentHashMap<>();
private Session session;
private String username;
@OnOpen public void onOpen(Session session, @PathParam("username") String username) { this.session = session; this.username = username; clients.put(username, this); addOnlineCount(); System.out.println("用户[" + username + "]连接,当前在线人数:" + getOnlineCount());
sendMessage("连接成功!当前在线人数:" + getOnlineCount()); }
@OnClose public void onClose() { clients.remove(username); subOnlineCount(); System.out.println("用户[" + username + "]断开连接,当前在线人数:" + getOnlineCount()); }
@OnMessage public void onMessage(String message, Session session) { System.out.println("收到用户[" + username + "]的消息:" + message);
for (WebSocketServer client : clients.values()) { client.sendMessage("用户[" + username + "]:" + message); } }
@OnError public void onError(Session session, Throwable error) { System.err.println("用户[" + username + "]发生错误"); error.printStackTrace(); }
public void sendMessage(String message) { try { this.session.getBasicRemote().sendText(message); } catch (IOException e) { e.printStackTrace(); } }
public static synchronized int getOnlineCount() { return onlineCount; } public static synchronized void addOnlineCount() { WebSocketServer.onlineCount++; } public static synchronized void subOnlineCount() { WebSocketServer.onlineCount--; } }
|