websocket是什么以及它要怎么用

WebSocket 实时通知机制
在高并发、异步下单场景中,它是提升用户体验、降低轮询压力的关键组件。
接下来会从原理讲清楚,再结合“秒杀活动”落地展示完整的前后端交互与代码实现(Java Spring Boot + 前端示例)。


一、WebSocket 是什么?

WebSocket 是一种在浏览器和服务器之间建立「全双工、持久连接」的通信协议
与传统 HTTP 不同,HTTP 是短连接、请求响应式的;而 WebSocket 建立连接后,服务器可以主动推送消息给客户端,不需要客户端轮询。

🔁 对比传统 HTTP 轮询

特点HTTP 轮询WebSocket
连接模式 短连接,请求-响应 持久连接,双向通信
服务器能否主动发消息 ❌ 不能 ✅ 可以
性能 频繁请求,压力大 长连接,轻量、实时
适用场景 请求量小、实时性低 聊天、订单状态、秒杀、行情推送

二、在「秒杀活动」中为什么用 WebSocket?

在你的秒杀设计中:

  • 用户点击“立即抢购” → 系统用 Redis + MQ 异步下单

  • 请求立即返回 "QUEUED" 状态;

  • 后端在队列消费者落单后,才知道成功或失败。

如果不用 WebSocket:

  • 用户只能轮询 GET /seckill/status?messageId=...

  • 并发量高时,会造成 Web 层 + Redis + DB 压力。

如果用 WebSocket:

  • 用户请求秒杀后,保持 WebSocket 长连接;

  • 后端消费者落单完成时,通过 WebSocket 通道主动推送订单状态变更

  • 用户即时看到结果,不需要反复刷新。

👉 实时、节流、省资源。


三、WebSocket 在秒杀系统中的使用流程(图解)

        ┌──────────────────────┐│       浏览器端        ││   1. 建立 WebSocket  ││   2. 发送秒杀请求     ││   3. 等待推送结果     │└──────────┬───────────┘│WebSocket 连接│┌──────────▼──────────┐│   秒杀服务 (Spring)  ││ - 维护连接映射表     ││ - 通过 MQ 消费结果   ││ - 推送状态到客户端   │└──────────┬───────────┘│MQ/Rabbit│┌──────────▼──────────┐│     消费者服务       ││ - 创建订单           ││ - 发送结果通知       │└──────────────────────┘

四、详细实现(Java + 前端)

🔹 前端实现(示例)

假设前端是一个简单的 Vue / HTML 页面。

<!DOCTYPE html>
<html>
<head><title>秒杀活动</title>
</head>
<body><h2>秒杀活动</h2><button id="buyBtn">立即抢购</button><div id="status"></div><script>const userId = "user_123";const ws = new WebSocket(`ws://localhost:8080/ws/seckill/${userId}`);
ws.onopen = () => {console.log("✅ WebSocket connected");};ws.onmessage = (event) => {const msg = JSON.parse(event.data);if (msg.type === "ORDER_STATUS") {document.getElementById("status").innerText = "订单状态: " + msg.status;}};document.getElementById("buyBtn").onclick = async () => {const res = await fetch("/api/seckill/buy?eventId=1001&userId=" + userId, {method: "POST"});const data = await res.json();document.getElementById("status").innerText = "请求结果: " + data.status;};</script>
</body>
</html>

说明:

  • 页面在加载时与服务器建立 WebSocket 长连接;

  • 当用户点击“立即抢购”后,发起 HTTP 下单请求;

  • 后端在订单异步完成后,通过 WebSocket 主动推送消息;

  • 前端即时更新显示。


🔹 后端实现(Spring Boot)

我们需要三个部分:

  1. WebSocket 服务端(负责连接与推送)

  2. 秒杀请求 Controller(发起秒杀逻辑)

  3. 订单消费者(异步落单后推送结果)


1️⃣ WebSocket 配置与服务端类

// WebSocketConfig.java
@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {@Overridepublic void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {registry.addHandler(new SeckillWebSocketHandler(), "/ws/seckill/{userId}").setAllowedOrigins("*"); // 生产环境记得做白名单
    }
}
// SeckillWebSocketHandler.java
@Component
public class SeckillWebSocketHandler extends TextWebSocketHandler {// 存储所有用户连接(简单实现,可换为 Redis + Channel 分布式映射)private static final Map<String, WebSocketSession> userSessions = new ConcurrentHashMap<>();@Overridepublic void afterConnectionEstablished(WebSocketSession session) {String userId = getUserId(session);userSessions.put(userId, session);System.out.println("用户 " + userId + " 已连接");}@Overridepublic void afterConnectionClosed(WebSocketSession session, CloseStatus status) {String userId = getUserId(session);userSessions.remove(userId);System.out.println("用户 " + userId + " 已断开");}private String getUserId(WebSocketSession session) {return session.getUri().getPath().split("/ws/seckill/")[1];}public void sendMessageToUser(String userId, String message) {WebSocketSession session = userSessions.get(userId);if (session != null && session.isOpen()) {try {session.sendMessage(new TextMessage(message));} catch (IOException e) {e.printStackTrace();}}}
}

2️⃣ 秒杀 Controller(异步下单 + 即时返回) 

@RestController
@RequestMapping("/api/seckill")
public class SeckillController {@Autowiredprivate MessageQueueProducer mqProducer;@Autowiredprivate SeckillWebSocketHandler wsHandler;@PostMapping("/buy")public ResponseEntity<?> buy(@RequestParam Long eventId, @RequestParam String userId) {// 假设 Redis 校验逻辑已经通过String messageId = UUID.randomUUID().toString();SeckillMessage msg = new SeckillMessage(messageId, eventId, userId);// 发送异步消息给 MQmqProducer.send("seckill-topic", msg);// 立即通知前端:排队中wsHandler.sendMessageToUser(userId, "{\"type\":\"ORDER_STATUS\", \"status\":\"QUEUEING\"}");return ResponseEntity.ok(Map.of("status", "QUEUED", "messageId", messageId));}
}

3️⃣ 消费者处理(模拟异步下单完成后推送结果)

@Component
public class SeckillConsumer {@Autowiredprivate SeckillWebSocketHandler wsHandler;// 模拟从 MQ 消费到消息@RabbitListener(queues = "seckill-queue")public void handleSeckill(SeckillMessage msg) throws Exception {System.out.println("消费到秒杀消息:" + msg);Thread.sleep(2000); // 模拟落单耗时// 模拟结果(成功/失败)boolean success = Math.random() > 0.2;String status = success ? "SUCCESS" : "FAILED";// 通知前端(WebSocket 推送)
        wsHandler.sendMessageToUser(msg.getUserId(),String.format("{\"type\":\"ORDER_STATUS\", \"status\":\"%s\", \"orderNo\":\"%s\"}",status, msg.getMessageId()));}
}

五、WebSocket 在秒杀系统中的优势

优势描述
✅ 实时性强 MQ 消费完成立刻推送结果给前端
✅ 降低轮询压力 不需要前端频繁 GET /status
✅ 提升体验 用户感觉“抢购完立刻知道结果”
✅ 可扩展 支持多用户连接、广播通知等
⚠️ 注意 要做断线重连与分布式会话管理

六、生产实践中要考虑的问题

问题解决方案
WebSocket 连接量大(百万用户) Netty / Gateway 分发层 维护长连接(例如 Spring WebFlux 或 IM 服务)
多实例部署时如何路由用户连接 用 Redis Pub/Sub 或 Kafka 通知其他实例转发消息
用户断线怎么办 前端定时重连 + 状态轮询兜底
安全性 WebSocket 握手时带 Token 鉴权,不允许匿名连接

七、总结

WebSocket 在秒杀系统中的角色:

“让用户在异步下单模型下实时获知订单状态,替代高频轮询。”

典型实现路径:

  1. 用户进入活动页 → 建立 WebSocket;

  2. 点击抢购 → HTTP 调用 /buy;

  3. 后端 Redis + MQ 异步落单;

  4. 消费端完成后 → 通过 WebSocket 主动推送结果;

  5. 前端即时显示成功/失败。

典型技术栈:

  • 后端: Spring Boot + WebSocket + MQ (Rabbit/Kafka)

  • 前端: WebSocket API + 状态 UI 更新

  • 连接管理: Redis Pub/Sub + Session 映射

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/953888.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日一题:第474场周赛 Q1. 找出缺失的元素

给你一个整数数组 nums ,数组由若干 互不相同 的整数组成。 数组 nums 原本包含了某个范围内的 所有整数 。但现在,其中可能 缺失 部分整数。 该范围内的 最小 整数和 最大 整数仍然存在于 nums 中。 返回一个 有序 …

上一次的参考文献

Charles M, Ochieng S B. Strategic outsourcing and firm performance: a review of literature[J]. International Journal of Social Science and Humanities Research (IJSSHR) ISSN, 2023, 1(1): 20-29. Kocot D,…

思维的漫游者:叙事性所揭示的非目的性心智

思维的漫游者:叙事性所揭示的非目的性心智 我们习惯于将思维描绘成一个猎手:带着明确的问题,在知识的森林中进行“强势搜索”,直至捕获答案。然而,“内观照叙事模型”所揭示的思维图景,更像一个漫游的诗人——它…

C++练习02

//计算复数 #include <iostream> #include <iomanip> using namespace std; typedef struct{float x;float y; }Comp; //打印复数的函数 void Printer(Comp res) {if (res.x == 0 && res.y == 0) …

软件技术基础

项目 内容这个作业属于哪个课程 https://edu.cnblogs.com/campus/zjlg/25rjjc这个作业的目标 实现一个命令行文本计数统计程序姓名 - 学号 周嘉俊 - 2023329301123码云仓库地址 https://gitee.com/rt666666/wc.exe

I2C to 16-Bit GPIO Expander with Interrupt TPT29555A

The TPT29555A is a 16-bit GPIO expander with interruption and weak pull-up resistors for I2C-bus applications. The power supplier voltage range is from 1.65 V to 5.5 V, allowing the TPT29555A to interc…

2025年数据分类分级工具选型指南:智能合规基座与八大产品全景评估

2025年数据分类分级工具选型指南:智能合规基座与八大产品全景评估基于对八款主流产品的深度测试与评估,AI-FOCUS团队研发的成竹AI数据分类分级助手在综合智能化程度、部署灵活性、硬件要求与成本可控性方面表现卓越,…

国产化数据库迁移工具不会用?教你手搓一个万能数据迁移工具。

国产化数据库迁移工具不会用?教你手搓一个万能数据迁移工具。手搓数据库迁移工具需要考虑迁移的数据量、源数据库和目标数据库的类型、版本和兼容性等问题,使用SOD框架可以很方便的解决这些问题。为什么要手搓一个自…

【UE引擎解构】- 引擎基础 :基本组件

前言: UE推崇"组合大于继承"的思路,因此组件在UE中代表功能的具体载体 "UActorComponent 是所有组件的基类。由于组件是渲染网格体和图像、实现碰撞和播放音频的唯一方法,因此玩家游戏期间在场景中看…

思维的“幽灵显影”:神经科学捕捉意义重燃的独特签名

思维的“幽灵显影”:神经科学捕捉意义重燃的独特签名 我们都有过这样的体验:一个被打断的念头,在数小时后悄然复现,并瞬间接续。传统科学将其解释为记忆的简单“提取”。然而,一项基于“内观照叙事模型”的新假说…

搜索百科(6):Meilisearch — Rust 打造的轻量级搜索新锐

《搜索百科》专栏系列,本文主要介绍 Meilisearch,它是一个使用 Rust 语言编写的开源、轻量级搜索引擎,以其极致的性能、简单的部署和友好的开发者体验而闻名。Meilisearch 不基于 Lucene,采用全新的架构设计,特别…

软件工程--团队作业

作业信息:这个作业属于哪个课程 首页 - 计科23级34班 - 广东工业大学 - 班级博客 - 博客园这个作业要求在哪里 团队作业1——团队展示&选题 - 作业 - 计科23级34班 - 班级博客 - 博客园这个作业的目标 组建团队 ; …

C++练习1

#include <stdio.h>struct complex{int real;int imag; };//结构体定义:分为实部和虚部struct complex multiply(struct complex x, struct complex y); //函数声明 int main() {struct complex product, x, y;…

2025.11.2总结

今天继续软考的学习,学设计模式的时候学不动了,稍微记一下三大类,23种,创建型5种,结构型7种,行为型11种。还行 创建型五种,也记住了工厂方法模式,抽象工厂模式,建造者模式,原型,单例模式。概念过了一遍,背…

第二届数证杯初赛-计算机取证

第二届数证杯初赛 容器密码:GQ7aXryvOCM8qGeXa19K9g&jtHSGtrimps@QxaYt4oRwwKHeN0A$#EPv*u 计算机取证分析 请根据计算机检材…

视频瘦身大师

视频瘦身大师 一、作业基本信息 项目名称:视频瘦身大师这个项目属于哪个课程 https://edu.cnblogs.com/campus/gdgy/Class34Grade23ComputerScience/作业要求 https://edu.cnblogs.com/campus/gdgy/Class34Grade23Com…

如何把应用程序的图标都摆在xfce的panel上

如何把应用程序的图标都摆在xfce的panel上鼠标右键——面板首选项——项目,可以添加多个启动器。 每个启动器的属性里可以添加多个应用程序。如果应用程序过多(比如3个),就会显示上箭头。

claude_code_clone

claude_code_clone https://github.com/fanqingsong/claude_code_cloneClaude-Code-Clone — LangGraph CLI Coding agentA compact, runnable Python project that reconstructs a demo agent using LangGraph, LangC…

CF2035E

有两种操作,第一种代价 \(x\),第二种 \(y\)。在不能连续进行 \(1\) 操作 \(k\) 次的情况下,问至少需要多少代价才能打出至少 \(z\) 点伤害。使攻击力 \(d\) 加 \(1\)(初始为 \(0\))。 打出 \(d\) 点伤害。\(1 \le…

puty总是自动断开连接,修改配置即可

然后接下来是重点,你需要点击Session,并且选择Default Sessions,然后点旁边的保存才可以, 要不然根本保存不下来,小坑