python基于FastAPI实现一个简易的在线用户统计功能

 更新时间:2025年10月24日 15:34:16   作者:Love丶伊卡洛斯  
这篇文章主要为大家详细介绍了一个基于Python的FastAPI框架实现的服务,用于统计客户端的心跳信息,并据此维护在线用户列表以及记录活跃用户数,感兴趣的小伙伴可以了解下

概述

这是一个基于Python的FastAPI框架实现的服务,用于统计客户端的心跳信息,并据此维护在线用户列表以及记录活跃用户数。

功能特性

  • 心跳接收:接受来自客户端的心跳包,以更新客户端的状态。
  • 在线用户统计:提供API接口来获取当前在线用户的数量。
  • 活跃用户统计:提供API接口来获取最近指定天数内活跃的用户数量。
  • 请求频率限制:对每个IP地址实施每秒一次的请求频率限制。

安装与运行

请确保已经安装了Python 3.10+。

克隆或下载项目源代码到本地。

在项目根目录下安装所需的依赖库:

pip install fastapi uvicorn

运行服务:

python main.py

或者使用uvicorn命令直接运行(假设文件名为main.py):

uvicorn main:app --reload --host 0.0.0.0 --port 8001

API 文档

http://127.0.0.1:8001/docs

心跳接收

  • URL: /heartbeat
  • 方法: POST
  • 描述: 接收客户端发送的心跳信号,并更新客户端为在线状态。
  • 响应:
    • 200 OK: 返回JSON格式的信息确认收到心跳。
    • 429 Too Many Requests: 如果客户端在1秒内发送了多个请求。

获取在线用户数量

  • URL: /online_clients
  • 方法: POST
  • 描述: 返回当前在线的客户端数量。
  • 响应:
    • 200 OK: 返回包含在线用户数量的JSON对象。
    • 429 Too Many Requests: 请求过于频繁。

获取活跃用户数量

  • URL: /total_users
  • 方法: GET 或 POST
  • 参数:
    • days (可选, 默认值为7): 指定要查询的天数。
  • 描述: 返回最近几天内有活动记录的用户数量。
  • 响应:
    • 200 OK: 返回包含活跃用户数量和查询天数的JSON对象。
    • 429 Too Many Requests: 请求过于频繁。

数据存储

所有客户端的心跳时间戳将被持久化到一个JSON文件中,该文件位于服务启动时所在的目录下的users_data.json。每次接收到新的心跳信号时,都会更新此文件。

注意事项

  • 本服务仅用于演示目的,实际生产环境中可能需要考虑更健壮的数据存储解决方案、安全性增强措施等。
  • 为了保护服务器免受滥用,已实施了基本的请求频率限制。根据实际需求,可以调整这个限制。
  • 服务默认监听在8001端口上,可以通过修改uvicorn.run函数中的port参数来更改。

希望这份文档能对你有所帮助!如果有任何问题或需要进一步的帮助,请随时告诉我。

源码 main.py

from fastapi import FastAPI, Request, Depends, HTTPException
from collections import defaultdict
from datetime import datetime, timedelta
import asyncio
import json
import os

app = FastAPI()

# 存储客户端的心跳数据
clients_last_heartbeat = defaultdict(datetime)

# 每个IP请求时间间隔限制为1秒
last_request_time = defaultdict(datetime)

# 在线客户端统计
online_clients = set()

# 心跳超时时间设置为1分钟
HEARTBEAT_TIMEOUT = timedelta(minutes=10)

# 用户数据文件路径
USER_DATA_FILE = "users_data.json"

# 加载用户数据
def load_user_data():
    if os.path.exists(USER_DATA_FILE):
        with open(USER_DATA_FILE, "r") as f:
            return json.load(f)
    return {}

# 保存用户数据
def save_user_data(data):
    with open(USER_DATA_FILE, "w") as f:
        json.dump(data, f)

# 初始化用户数据
all_users = load_user_data()

@app.on_event("startup")
async def startup_event():
    # 启动后台任务,每1分钟检查一次在线设备
    asyncio.create_task(remove_offline_clients())

async def remove_offline_clients():
    """
    定时任务:移除超过心跳超时时间未发送心跳的客户端
    """
    while True:
        await asyncio.sleep(HEARTBEAT_TIMEOUT.total_seconds())
        now = datetime.utcnow()
        # 找出超过超时时间未发送心跳的设备,并将其从在线列表中移除
        offline_clients = {ip for ip, last_heartbeat in clients_last_heartbeat.items()
                           if now - last_heartbeat > HEARTBEAT_TIMEOUT}
        
        # 从在线设备中移除离线的客户端
        for client in offline_clients:
            online_clients.discard(client)
            del clients_last_heartbeat[client]  # 删除心跳记录

        print(f"清除离线客户端, 当前在线客户端数量: {len(online_clients)}")

# 请求频率限制,1秒内只能请求一次
def request_limit(request: Request):
    client_ip = request.client.host
    now = datetime.utcnow()
    
    if client_ip in last_request_time and (now - last_request_time[client_ip]).total_seconds() < 1:
        raise HTTPException(status_code=429, detail="Too Many Requests")
    
    last_request_time[client_ip] = now

@app.post("/heartbeat")
async def receive_heartbeat(request: Request, limit: None = Depends(request_limit)):
    """
    接受客户端的心跳包
    """
    client_ip = request.client.host
    now = datetime.utcnow()
    # 更新心跳时间并将客户端标记为在线
    clients_last_heartbeat[client_ip] = now
    online_clients.add(client_ip)
    
    # 更新所有用户数据并保存到文件
    all_users[client_ip] = now.isoformat()
    save_user_data(all_users)
    
    return {"message": "Heartbeat received", "ip": client_ip}

@app.get("/online_clients")
async def get_online_clients(request: Request, limit: None = Depends(request_limit)):
    """
    获取当前在线客户端数量
    """
    return {"online_clients_count": len(online_clients)}

@app.post("/online_clients")
async def get_online_clients2(request: Request, limit: None = Depends(request_limit)):
    """
    获取当前在线客户端数量
    """
    return {"online_clients_count": len(online_clients)}

@app.get("/total_users")
async def get_total_users(days: int = 7, request: Request = None, limit: None = Depends(request_limit)):
    """
    获取最近n天活跃的用户数
    """
    now = datetime.utcnow()
    cutoff_date = now - timedelta(days=days)
    
    # 筛选最近n天活跃的用户
    recent_users_count = sum(
        1 for last_seen in all_users.values()
        if datetime.fromisoformat(last_seen) >= cutoff_date
    )
    
    return {"recent_users_count": recent_users_count, "days": days}

if __name__ == '__main__':
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8001)


到此这篇关于python基于FastAPI实现一个简易的在线用户统计功能的文章就介绍到这了,更多相关python统计在线用户内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Python实现ping指定IP的示例

    Python实现ping指定IP的示例

    今天小编就为大家分享一篇Python实现ping指定IP的示例,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-06-06
  • 在Python的Django框架的视图中使用Session的方法

    在Python的Django框架的视图中使用Session的方法

    这篇文章主要介绍了在Python的Django框架的视图中使用Session的方法,包括相关的设置测试Cookies的方法,需要的朋友可以参考下
    2015-07-07
  • Pytest+Yaml+Excel 接口自动化测试框架的实现示例

    Pytest+Yaml+Excel 接口自动化测试框架的实现示例

    本文主要介绍了Pytest+Yaml+Excel 接口自动化测试框架,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-01-01
  • Python自动化测试之登录脚本的实现

    Python自动化测试之登录脚本的实现

    本文主要介绍了Python自动化测试之登录脚本的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-02-02
  • Python装饰器用法实例总结

    Python装饰器用法实例总结

    这篇文章主要介绍了Python装饰器用法,结合实例形式总结分析了Python常用装饰器的概念、功能、使用方法及相关注意事项,需要的朋友可以参考下
    2018-02-02
  • Python中TK窗口的创建方式

    Python中TK窗口的创建方式

    这篇文章主要介绍了Python中TK窗口的创建方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-11-11
  • Python实现字典转字符串的五种方法

    Python实现字典转字符串的五种方法

    本文介绍了在Python中如何将字典数据结构转换为字符串格式的多种方法,首先可以通过内置的str()函数进行简单转换;其次利用ison.dumps()函数能够更灵活地控制输出格式;最后还提供了使用格式化字符串手动转换的示例,需要的朋友可以参考下
    2025-09-09
  • 使用Python手工计算x的算数平方根,来自中国古人的数学智慧

    使用Python手工计算x的算数平方根,来自中国古人的数学智慧

    本篇采用的计算方法既非二分法也非牛顿迭代法,而是把中国古代的手工计算平方根的方法转成代码来完成。代码有点烦杂,算是抛砖引玉吧,期待高手们写出更好的代码来
    2021-09-09
  • 详解Python和Rust中内存管理机制的实现与对比

    详解Python和Rust中内存管理机制的实现与对比

    Python和Rust都采用了垃圾收集(Garbage Collection)机制来管理内存,但它们各自的实现方式有很大的不同,下面就跟随小编一起来深入了解下二者的区别吧
    2024-03-03
  • Python实现快速大文件比较代码解析

    Python实现快速大文件比较代码解析

    这篇文章主要介绍了Python实现快速大文件比较代码解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09

最新评论