【Redis实战】快速简单搭建聊天室04——实现页面功能

本文涉及的产品
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
云数据库 Tair(兼容Redis),内存型 2GB
简介: 【Redis实战】快速简单搭建聊天室04——实现页面功能

实现获取聊天消息的功能


聊天消息保存在Redis里名为“chat_list”列表中,新的消息在列表右侧,老的消息在列表左侧。每次返回最右侧的20条信息。获取聊天消息的功能对应的方法为get_chat_list()。修改这个方法,实现获取消息列表:

01    def get_chat_list(self):
02        """
03        你需要实现这个方法
04     
05        获取聊天消息列表。
06        使用Redis的列表实现。Key为self.chat_list属性中保存的字符串,可以直接使用。
07        获取列表右端20条信息,但不要删除。
08     
09        需要注意,从Redis中获取的数据一个列表,列表里面是bytes型的字符串,所以需要
10        先把这个列表展开,把里面的bytes型的字符串解密为普通字符串以后再用json解析为
11        字典。接下来讲解析出来的字典放入一个新的列表中。最后返回新的列表。
12        :return: 包含字典的列表
13        """
14        chat_list = self.client.lrange(self.chat_list, -20, -1)
15        chat_info_list = []
16        for chat in chat_list:
17            chat_info = json.loads(chat.decode())
18            chat_info_list.append(chat_info)
19        return chat_info_list


其中,主要说明如下:

  • 14行:使用列表的lrange命令获取但不删除列表中的信息。-20表示从右往左数第20条信息,-1表示最右边的信息
  • 16-18行:由于lrange返回的数据是包含bytes型数据的列表,所以需要把列表里的每一条bytes的数据先解码为字符串,再用JSON模块解析为字典
  • 19行:将最终生成的包含字典的列表返回

                                             

获取聊天信息


修改完成代码以后重启网站,可以看到聊天室消息还是一片空白。现在,人工向Redis中添加几天数据:

01    127.0.0.1:6379> lpush chat_list '{"msg": "我是人工添加的消息", "nick": "青南", "post_time": "2018-07-22 16:15:00"}'
02    (integer) 1
03    127.0.0.1:6379> lpush chat_list '{"msg": "我是青南的助手", "nick": "青南的助手", "post_time": "2018-07-22 16:15:00"}'
04    (integer) 2
05    127.0.0.1:6379>





redis-cli中手动添加聊天信息


添加好聊天信息以后,可以看到聊天室里已经出现了手动添加的内容。

手动添加的内容已经出现在聊天窗口


2. 实现发送新信息的功能

发送新信息的原理非常简单,把新信息字典转换为JSON格式并存入chat_list列表的右侧即可。发现信息对应的方法为push_chat_info(),完善它的代码:


01    def push_chat_info(self, chat_info):
02        """
03        把聊天信息存入列表的右侧。
04     
05        使用Redis的集合实现,对应的Key为self.chat_list中保存的字符串。
06        把chat_info字典先转化为JSON字符串,再存入Redis中列表中。
07     
08        为了防止列表消息太长,因此需要使用ltrim命令删除多余的信息,只保留
09        列表最右侧的20条
10        :param chat_info: 字典,格式为{'msg': '信息', 'nick': '青南', 'post_time': '2018-07-22 10:00:12'}
11        :return: None
12        """
13        self.client.rpush(self.chat_list, json.dumps(chat_info))
14        self.client.ltrim(self.chat_list, -20, -1)

其中,主要说明如下:

  • 13行:先把聊天信息对应的字典转换为JSON字符串。然后添加的列表的右侧
  • 14行:chat_list列表只保留最右侧的20条,多余的信息全部删除

这里引入一个新的知识点,列表的ltrim命令。这个命令的作用是从列表里面删除保留一段数据并删除其他数据。

代码第14行调用ltrim命令,传入了三个参数。

第一个参数是列表的Key。

第二个参数是保留数据起始位置,第三个参数是保留数据截至位置。所以这一行代码的作用是除了右边数第20条数据(含)到右边第一条数据(含)外,删除列表中的其他数据。

本项目使用ltrim是为了节约服务器内存,加速读取列表的时间。这并不是必需的,如果服务器内存足够的话,或者信息不多的话,也可以不删除。


实现发布新信息的功能


修改完成代码以后网站,可以看到发帖功能已经正常。

发帖功能开发完成


到目前为止基本功能已经开发完成,但还有一个小问题需要解决。

用户无限制刷屏


如果不限制同一个用户发送同一条信息的频率,可能会出现一个用户短时间发送大量相同信息的刷屏的行为。



3. 设定刷屏检查字符串

本项目将会限制同一个昵称发送完全相同信息的频率。两次完全相同的信息的发送时间间隔为120秒。

Redis天然就具有实现这一功能的能力。在Redis中,Key可以设置过期时间。时间到了以后Redis会自动删除这个Key

那么如果设置一个字符串,Key为:“昵称-发言内容”。

例如“青南-我在灌水”。然后把这个Key的过期时间设置为120秒。这个字符串的值无所谓,随便设置什么都可以。那么只要这个KeyRedis中,就说明这个用户昵称,在120秒内已经发送过这条信息了。只要这个Key不在Redis中,就说明这个用户从来没有发送过这条信息或者发送已经超过了两分钟,KeyRedis自动删除了。

而且Redis可以使用ttl命令查询一个Key的过期时间还剩多少秒。这样还可以实现提醒功能。

设置Key的过期时间,对应的方法为set_nick_msg_expire_time()修改代码:


01    def set_nick_msg_expire_time(self, nick, msg):
02        """
03        你需要实现这个方法
04     
05        设定Key的过期时间,这个功能的目的是限定同一个用户在2分钟内不能发送同样的内容。
06        为了防止信息太长,因此把信息编码为md5以后再与昵称拼接以缩短Key的长度。
07        使用Redis的字符串实现,字符串的Key为昵称+信息的md5编码,值为1.使用set命令的
08        ex参数设定Key的过期时间为120秒,时间到了以后Redis会自动删除这个Key
09        :param nick: 昵称
10        :param msg: 信息
11        :return: None
12        """
13        msg_md5 = hashlib.md5(msg.encode()).hexdigest()
14        duplicate_msg_check_flag = nick + msg_md5
15        self.client.set(duplicate_msg_check_flag, 1, ex=120)

13行:先把信息转换为MD5。这样做的好处是缩短信息的长度,避免太长到信息导出超出Redis Key的限制

14行:把用户昵称与消息的MD5值拼成一个长字符串,作为Key

15行:Redis中设定一个字符串,Key为昵称与消息的MD5值,值为1,通过ex参数设定过期时间为120,过期时间一到Redis就会删除这个Key


设定刷屏检查字符串及其过期时间



4、读取刷屏限制剩余时间

当用户要发送新内容的时候,网站先检查Redis是否有“昵称+新信息MD5值”这个Key,如果有,说明用户在120秒类发送了相同的内容,此时返回解除刷屏限制的剩余时间。如果不存在这个Key,就返回None。对应的方法为get_nick_msg_expire_time()。修改现有代码:

01    def get_nick_msg_expire_time(self, nick, msg):
02        """
03        获取某一个昵称发送某一条消息的过期时间。这个功能的作用是
04        为了防止同一个用户短时间发送大量相同信息刷屏。
05     
06        为了防止信息太长,因此把信息编码为md5以后再与昵称拼接以缩短Key的长度。
07        使用Redis的ttl命令来实现,ttl命令如果返回None,说明不存在这个Key,
08        返回None。如果ttl返回-1,说明这个Key没有设定过期时间,这个Key可以一直存在
09        如果ttl返回一个大于0的正整数,说明在这个整数对应的秒过于以后,Redis会自动
10        删除这个Key
11     
12        :param nick: 昵称
13        :param msg: 信息
14        :return: None 或者 数字
15        """
16        msg_md5 = hashlib.md5(msg.encode()).hexdigest()
17        duplicate_msg_check_flag = nick + msg_md5
18        expire_time = self.client.ttl(duplicate_msg_check_flag)
19        return expire_time

其中,主要说明如下:

  • 16行:获得消息的MD5
  • 17行:把昵称与消息的MD5值拼成一个Key
  • 使用Redisttl命令检查Key的剩余时间。如果Key不存在,返回None,如果Key没有过期时间,返回-1,如果Key有过期时间,返回剩余时间(正整数)


读取刷屏限制过期时间


修改完成以后重启网站,尝试连续发送相同的信息,发现得到网站提示。

提示不能在两分钟内发送同样的内容


5、总结

本系列推送通过开发简易聊天室网站来巩固Redis的基础知识。同时也引入了列表裁剪,Key添加过期时间与检查Key剩余过期时间这三个知识点。读者在开发的过程中,可以经常使用redis-cli观察Redis中的Key的变化情况,以便于更好理解代码和命令的作用。

目录
相关文章
|
11天前
|
存储 NoSQL 前端开发
Redis专题-实战篇一-基于Session和Redis实现登录业务
本项目基于SpringBoot实现黑马点评系统,涵盖Session与Redis两种登录方案。通过验证码登录、用户信息存储、拦截器校验等流程,解决集群环境下Session不共享问题,采用Redis替代Session实现数据共享与自动续期,提升系统可扩展性与安全性。
86 3
Redis专题-实战篇一-基于Session和Redis实现登录业务
|
11天前
|
存储 缓存 NoSQL
Redis专题-实战篇二-商户查询缓存
本文介绍了缓存的基本概念、应用场景及实现方式,涵盖Redis缓存设计、缓存更新策略、缓存穿透问题及其解决方案。重点讲解了缓存空对象与布隆过滤器的使用,并通过代码示例演示了商铺查询的缓存优化实践。
75 1
Redis专题-实战篇二-商户查询缓存
|
6月前
|
数据采集 存储 数据可视化
分布式爬虫框架Scrapy-Redis实战指南
本文介绍如何使用Scrapy-Redis构建分布式爬虫系统,采集携程平台上热门城市的酒店价格与评价信息。通过代理IP、Cookie和User-Agent设置规避反爬策略,实现高效数据抓取。结合价格动态趋势分析,助力酒店业优化市场策略、提升服务质量。技术架构涵盖Scrapy-Redis核心调度、代理中间件及数据解析存储,提供完整的技术路线图与代码示例。
604 0
分布式爬虫框架Scrapy-Redis实战指南
|
3月前
|
缓存 监控 NoSQL
Redis 实操要点:Java 最新技术栈的实战解析
本文介绍了基于Spring Boot 3、Redis 7和Lettuce客户端的Redis高级应用实践。内容包括:1)现代Java项目集成Redis的配置方法;2)使用Redisson实现分布式可重入锁与公平锁;3)缓存模式解决方案,包括布隆过滤器防穿透和随机过期时间防雪崩;4)Redis数据结构的高级应用,如HyperLogLog统计UV和GeoHash处理地理位置。文章提供了详细的代码示例,涵盖Redis在分布式系统中的核心应用场景,特别适合需要处理高并发、分布式锁等问题的开发场景。
274 41
|
1月前
|
存储 NoSQL Redis
采用Redis的Bitmaps实现类似Github连续提交状态的功能。
在现实世界的应用开发中,实现类似于Github提交跟踪系统时,还可能需要考虑用户时区、闰年等日期相关的边界条件,以及辅助数据的存储和查询优化,例如对活跃用户的即时查询和统计等。不过这些都可以在Bitmaps的基础功能之上通过额外的代码逻辑来实现。
69 0
|
3月前
|
缓存 NoSQL 算法
高并发秒杀系统实战(Redis+Lua分布式锁防超卖与库存扣减优化)
秒杀系统面临瞬时高并发、资源竞争和数据一致性挑战。传统方案如数据库锁或应用层锁存在性能瓶颈或分布式问题,而基于Redis的分布式锁与Lua脚本原子操作成为高效解决方案。通过Redis的`SETNX`实现分布式锁,结合Lua脚本完成库存扣减,确保操作原子性并大幅提升性能(QPS从120提升至8,200)。此外,分段库存策略、多级限流及服务降级机制进一步优化系统稳定性。最佳实践包括分层防控、黄金扣减法则与容灾设计,强调根据业务特性灵活组合技术手段以应对高并发场景。
1028 7
|
3月前
|
机器学习/深度学习 存储 NoSQL
基于 Flink + Redis 的实时特征工程实战:电商场景动态分桶计数实现
本文介绍了基于 Flink 与 Redis 构建的电商场景下实时特征工程解决方案,重点实现动态分桶计数等复杂特征计算。通过流处理引擎 Flink 实时加工用户行为数据,结合 Redis 高性能存储,满足推荐系统毫秒级特征更新需求。技术架构涵盖状态管理、窗口计算、Redis 数据模型设计及特征服务集成,有效提升模型预测效果与系统吞吐能力。
341 2
|
4月前
|
消息中间件 缓存 NoSQL
基于Spring Data Redis与RabbitMQ实现字符串缓存和计数功能(数据同步)
总的来说,借助Spring Data Redis和RabbitMQ,我们可以轻松实现字符串缓存和计数的功能。而关键的部分不过是一些"厨房的套路",一旦你掌握了这些套路,那么你就像厨师一样可以准备出一道道饕餮美食了。通过这种方式促进数据处理效率无疑将大大提高我们的生产力。
185 32
|
4月前
|
存储 监控 NoSQL
使用Redis实现延迟消息发送功能
使用 Redis 的密码认证功能,为实例设置密码以防止未授权访问。为消息提供适当加密,确保消息内容在网络传输过程中不被窃取或篡改。
189 16
|
NoSQL API Redis
redis的其他功能
瑞士军刀Redis image.png 慢查询 image.png image.png image.png image.
1111 0