前端WebSocket实战:别再只会用HTTP了

前端WebSocket实战:别再只会用HTTP了

前端WebSocket实战:别再只会用HTTP了

毒舌时刻

这代码写得跟网红滤镜似的——仅供参考。

各位前端同行,咱们今天聊聊前端WebSocket。别告诉我你还在用轮询获取实时数据,那感觉就像每隔一分钟就去敲门问"好了没"——烦人又低效。

为什么你需要WebSocket

最近看到一个项目,实时聊天功能用轮询实现,每秒请求一次服务器,我差点当场去世。我就想问:你是在做实时通信还是在做DDoS攻击?

反面教材

// 反面教材:轮询获取数据 function startPolling() { setInterval(async () => { const response = await fetch('/api/messages'); const messages = await response.json(); updateMessages(messages); }, 1000); // 每秒请求一次 } // 服务器:求放过 // 带宽:我扛不住了 

毒舌点评:这代码,我看了都替你的服务器着急。每秒轮询一次,你是想让服务器变成蜜蜂吗?

前端WebSocket的正确姿势

1. 基础WebSocket使用

// 正确姿势:基础WebSocket class WebSocketClient { constructor(url) { this.url = url; this.ws = null; this.reconnectAttempts = 0; this.maxReconnectAttempts = 5; this.listeners = new Map(); } connect() { this.ws = new WebSocket(this.url); this.ws.onopen = () => { console.log('WebSocket连接成功'); this.reconnectAttempts = 0; this.emit('open'); }; this.ws.onmessage = (event) => { const data = JSON.parse(event.data); this.emit(data.type, data.payload); }; this.ws.onclose = () => { console.log('WebSocket连接关闭'); this.emit('close'); this.reconnect(); }; this.ws.onerror = (error) => { console.error('WebSocket错误:', error); this.emit('error', error); }; } send(type, payload) { if (this.ws && this.ws.readyState === WebSocket.OPEN) { this.ws.send(JSON.stringify({ type, payload })); } } on(event, callback) { if (!this.listeners.has(event)) { this.listeners.set(event, []); } this.listeners.get(event).push(callback); } emit(event, data) { if (this.listeners.has(event)) { this.listeners.get(event).forEach(callback => callback(data)); } } reconnect() { if (this.reconnectAttempts < this.maxReconnectAttempts) { this.reconnectAttempts++; console.log(`尝试重连... (${this.reconnectAttempts}/${this.maxReconnectAttempts})`); setTimeout(() => this.connect(), 3000); } } disconnect() { if (this.ws) { this.ws.close(); } } } // 使用 const ws = new WebSocketClient('wss://api.example.com/ws'); ws.on('open', () => { console.log('连接成功'); }); ws.on('message', (data) => { console.log('收到消息:', data); }); ws.connect(); 

2. React中使用WebSocket

// 正确姿势:React中使用WebSocket import { useEffect, useRef, useState, useCallback } from 'react'; function useWebSocket(url) { const [isConnected, setIsConnected] = useState(false); const [messages, setMessages] = useState([]); const ws = useRef(null); useEffect(() => { ws.current = new WebSocket(url); ws.current.onopen = () => setIsConnected(true); ws.current.onclose = () => setIsConnected(false); ws.current.onmessage = (event) => { const data = JSON.parse(event.data); setMessages(prev => [...prev, data]); }; return () => { ws.current.close(); }; }, [url]); const sendMessage = useCallback((message) => { if (ws.current && ws.current.readyState === WebSocket.OPEN) { ws.current.send(JSON.stringify(message)); } }, []); return { isConnected, messages, sendMessage }; } // 使用 function ChatRoom() { const { isConnected, messages, sendMessage } = useWebSocket('wss://chat.example.com'); const [input, setInput] = useState(''); const handleSend = () => { sendMessage({ type: 'chat', content: input }); setInput(''); }; return ( <div> <div>状态: {isConnected ? '已连接' : '未连接'}</div> <div className="messages"> {messages.map((msg, i) => ( <div key={i}>{msg.content}</div> ))} </div> <input value={input} onChange={e => setInput(e.target.value)} /> <button onClick={handleSend}>发送</button> </div> ); } 

3. 使用Socket.io

// 正确姿势:使用Socket.io import { io } from 'socket.io-client'; const socket = io('https://api.example.com', { transports: ['websocket'], autoConnect: true, reconnection: true, reconnectionAttempts: 5, reconnectionDelay: 3000 }); // 连接事件 socket.on('connect', () => { console.log('连接成功, ID:', socket.id); }); // 断开连接 socket.on('disconnect', () => { console.log('连接断开'); }); // 监听消息 socket.on('message', (data) => { console.log('收到消息:', data); }); // 发送消息 socket.emit('chat message', { text: 'Hello' }); // 加入房间 socket.emit('join room', 'room-1'); // 离开房间 socket.emit('leave room', 'room-1'); 

毒舌点评:早这么写,你的实时通信早做好了。别告诉我你还在用轮询,那你还是趁早去用短信吧。

实战技巧:WebSocket指南

1. WebSocket使用场景

  • 实时聊天:即时通讯
  • 实时数据:股票、比分
  • 协同编辑:多人协作
  • 在线游戏:实时对战

2. 最佳实践

  1. 重连机制:断线自动重连
  2. 心跳检测:保持连接活跃
  3. 消息确认:确保消息送达
  4. 错误处理:优雅处理异常

最后想说的

WebSocket不是新技术,是实时通信的标准。别再只会用HTTP了——WebSocket一下,你的应用会实时起来。

WebSocket就像电话,HTTP就像写信。紧急的事打电话,不急的事写信。别什么事都写信,学会打电话。

Read more

【降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码】

【降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码】

降低 30% 开发成本:使用 Trae IDE 将 Figma 设计稿转化为前端代码_ide_葡萄城技术团队-葡萄城开发者空间 TRAE与Figma MCP:iOS原生应用UI自动生成的艺术-易源AI资讯 | 万维易源 Login | Figma 基于提供的Figma设计文件和网页链接,开发一个完整的前端网站项目。具体要求如下: 1. 页面展示要求: * 采用平铺式布局展示所有页面 * 严格遵循Figma设计稿中的视觉规范 * 实现IOS风格的高保真原型效果 * 确保所有交互元素与设计稿一致 2. 技术实现要求: * 使用现代前端框架(如React/Vue) * 实现响应式布局,适配不同设备 * 添加平滑的页面过渡动画 * 确保所有UI组件的高还原度 3. 交付物要求: * 完整的可运行前端代码 * 详细的部署文档 * 跨浏览器兼容性测试报告 * 性能优化方案 4. 质量标准: * 像素级还原设计稿 * 所有交互功能完整可用 * 代码符合最佳实践

用 Vue 3 重构 Dify 聊天前端(上篇):项目搭建与基础架构

用 Vue 3 重构 Dify 聊天前端(上篇):项目搭建与基础架构

本系列教程将带你从零开始,用 Vue 3 + TypeScript 复刻一个类似 Dify 的 AI 聊天前端。上篇聚焦项目搭建、类型设计、路由认证、HTTP 封装和状态管理。 项目简介 背景 Dify 是一个开源的 LLM 应用开发平台,提供了对话式 AI 的后端服务。在实际项目中,我们往往需要自建前端来对接Dify后端 API或LLM后端服务,实现定制化的聊天界面。 本项目的目标:用 Vue 3 构建一个生产级的 AI 聊天前端,具备以下能力: * SSE 流式输出(打字机效果) * Markdown 渲染 + 代码高亮 * 用户认证 * 文件/图片上传 * 聊天会话历史管理 * 工作流执行可视化 * Agent 思考过程展示 * 移动端响应式适配

零成本搭建飞书机器人:手把手教你用Webhook实现高效消息推送

1. 为什么你需要一个飞书机器人? 在日常工作中,我们经常需要处理各种通知需求。比如系统报警、任务提醒、审批结果通知等等。传统的解决方案包括短信、邮件或者第三方推送平台,但这些方式要么成本高,要么实时性差。飞书机器人提供了一种零成本、高效率的替代方案。 我去年负责的一个ERP系统升级项目就遇到了这个问题。当时我们需要在关键业务流程节点给不同部门的同事发送实时通知。如果使用短信,按照每天200条计算,一个月就要花费上千元。后来我们改用飞书机器人,不仅完全免费,还能实现更丰富的消息格式和精准的@提醒功能。 飞书机器人本质上是一个自动化程序,它通过Webhook技术接收外部系统的消息,并转发到指定的飞书群聊中。这种机制特别适合企业内部系统与飞书之间的集成,比如: * 运维报警通知 * 审批流程提醒 * 业务系统状态更新 * 日报/周报自动推送 * 数据监控预警 2. 5分钟快速创建你的第一个机器人 创建飞书机器人非常简单,不需要任何开发经验。下面我以电脑端操作为例,手把手带你完成整个过程。 首先打开飞书客户端,进入你想要添加机器人的群聊。点击右上角的"..."菜单,

Spring Boot 04 整合Web(上)

返回JSON数据 spring-boot-starter-web依赖默认加入了jackson-databind作为JSON处理器 创建实体类与Controller类,返回实体对象就行 默认的jackson-databind publicclassPeople{privateString name;@JsonIgnoreprivateString gender;@JsonFormat(pattern ="yyyy-MMM")privateLocalDate birthday;} @RestControllerpublicclassPeopleController{@GetMapping("/people")publicPeoplegetPeople(){People people =newPeople(); people.setName("张三"); people.setGender("男"); people.setBirthday(LocalDate.now());return people;}} 最终界面会打印如图数据 @JsonFormat规定了birthday的输