当前位置: 首页 > news >正文

FastAPI + MySQL + Redis 短链接生成与访问统计系统(含二维码)

FastAPI + MySQL + Redis 短链接生成与访问统计系统(含二维码)

涉及后端开发、缓存优化、数据统计和二维码生成等多个技术点。


🎯 核心功能模块

功能

说明

短链接生成

长URL → 唯一短码(如abc123

重定向跳转

访问短链接 → 302跳转到原始URL

访问统计

记录每次点击的IP、UA、时间、来源

二维码生成

为每个短链接生成二维码图片

过期管理

可设置短链接有效期

Redis加速

热点短链接缓存,降低数据库压力


🗄️ 数据库设计 (MySQL)

-- 短链接主表 CREATE TABLE short_links ( id BIGINT AUTO_INCREMENT PRIMARY KEY, short_code VARCHAR(8) NOT NULL UNIQUE, -- 短码 original_url TEXT NOT NULL, -- 原始URL created_at DATETIME DEFAULT CURRENT_TIMESTAMP, expires_at DATETIME NULL, -- 过期时间,NULL表示永久 is_active TINYINT DEFAULT 1, -- 是否启用 total_clicks INT DEFAULT 0, -- 总点击数(冗余字段) INDEX idx_short_code (short_code), INDEX idx_expires (expires_at) ); -- 访问日志表(用于统计分析) CREATE TABLE click_logs ( id BIGINT AUTO_INCREMENT PRIMARY KEY, short_code VARCHAR(8) NOT NULL, ip_address VARCHAR(45), user_agent TEXT, referer VARCHAR(500), country VARCHAR(100), device_type VARCHAR(20), -- PC/Mobile/Tablet clicked_at DATETIME DEFAULT CURRENT_TIMESTAMP, INDEX idx_code_time (short_code, clicked_at) );

⚡ Redis缓存策略

Key设计: - short:{code} → original_url (字符串,TTL=1小时) - stats:{code}:hourly → ZSET (每小时点击数,member=时间戳) - stats:{code}:daily → ZSET (每天点击数) 流程: 1. 请求短链接 → 先查Redis 2. 命中 → 直接返回URL,异步写日志到消息队列 3. 未命中 → 查MySQL,写入Redis,返回URL

🔧 FastAPI 后端实现

项目结构

shortlink_service/ ├── main.py ├── models.py # SQLAlchemy模型 ├── schemas.py # Pydantic模型 ├── crud.py # 数据库操作 ├── utils.py # 工具函数(短码生成、二维码) ├── routers/ │ ├── link.py # 短链接CRUD │ └── stats.py # 统计数据接口 └── templates/ └── qrcode.html # 二维码展示页面

关键代码示例

1. 短码生成算法 (utils.py)
import string, random import hashlib import base62 def generate_short_code(url: str, length: int = 6) -> str: """ 方法一:基于MD5截取 """ hash_obj = hashlib.md5(url.encode()) hex_digest = hash_obj.hexdigest() # 将16进制转为62进制(0-9a-zA-Z) decimal_val = int(hex_digest[:8], 16) return base62.encode(decimal_val)[:length] def generate_random_code(length: int = 6) -> str: """ 方法二:随机生成(需检查冲突) """ chars = string.ascii_letters + string.digits return ''.join(random.choices(chars, k=length))
2. 创建短链接接口 (routers/link.py)
from fastapi import APIRouter, Depends, HTTPException from sqlalchemy.orm import Session from .. import crud, schemas, utils from ..database import get_db from ..redis_client import redis_client router = APIRouter(prefix="/api/v1") @router.post("/shorten") async def create_short_link( req: schemas.ShortLinkCreate, db: Session = Depends(get_db) ): # 1. 生成短码 code = utils.generate_short_code(req.url) # 2. 检查冲突(极小概率) existing = crud.get_link_by_code(db, code) if existing: # 若冲突则重新生成(加盐) code = utils.generate_random_code() # 3. 写入数据库 link = crud.create_short_link(db, code, req.url, req.expire_days) # 4. 预热缓存 redis_client.setex(f"short:{code}", 3600, req.url) return { "short_code": code, "short_url": f"http://yourdomain.com/{code}", "original_url": req.url, "qrcode_url": f"/api/v1/qrcode/{code}" } @router.get("/{short_code}") async def redirect_to_url(short_code: str, request: Request, db: Session = Depends(get_db)): # 1. 从Redis获取 url = redis_client.get(f"short:{short_code}") if not url: # 2. 从DB获取 link = crud.get_active_link(db, short_code) if not link or (link.expires_at and link.expires_at < datetime.utcnow()): raise HTTPException(status_code=404, detail="Link expired or not found") url = link.original_url # 3. 写入缓存 redis_client.setex(f"short:{short_code}", 3600, url) # 4. 异步记录日志(使用后台任务) background_tasks.add_task(log_click, short_code, request) # 5. 更新总点击数(异步) background_tasks.add_task(crud.increment_clicks, db, short_code) # 6. 302重定向 return RedirectResponse(url=url, status_code=302)
3. 访问统计接口 (routers/stats.py)
@router.get("/stats/{short_code}") async def get_stats(short_code: str, period: str = "7d", db: Session = Depends(get_db)): """ period: 24h / 7d / 30d """ # 获取总点击数 link = crud.get_link_by_code(db, short_code) if not link: raise HTTPException(404) # 按时间粒度聚合 granularity = "hour" if period == "24h" else "day" raw_data = crud.get_click_timeline(db, short_code, period, granularity) # 设备分布 devices = crud.get_device_distribution(db, short_code) # 地域分布(需配合IP库) countries = crud.get_country_distribution(db, short_code) return { "total_clicks": link.total_clicks, "timeline": raw_data, "devices": devices, "countries": countries }
4. 二维码生成 (utils.py + router)
import qrcode from io import BytesIO from fastapi.responses import StreamingResponse def generate_qrcode(data: str) -> BytesIO: qr = qrcode.QRCode(box_size=10, border=4) qr.add_data(data) qr.make(fit=True) img = qr.make_image(fill_color="black", back_color="white") buf = BytesIO() img.save(buf, format="PNG") buf.seek(0) return buf @router.get("/qrcode/{short_code}") async def get_qrcode(short_code: str): short_url = f"http://yourdomain.com/{short_code}" buf = generate_qrcode(short_url) return StreamingResponse(buf, media_type="image/png")

📊 数据看板(ECharts示例)

你可以用FastAPI提供JSON数据,前端用ECharts展示:

// 每小时点击量柱状图 fetch(`/api/v1/stats/${code}?period=24h`) .then(res => res.json()) .then(data => { var chart = echarts.init(document.getElementById('chart')); chart.setOption({ title: { text: '过去24小时点击趋势' }, xAxis: { type: 'category', data: data.timeline.map(t => t.hour) }, yAxis: { type: 'value' }, series: [{ type: 'bar', data: data.timeline.map(t => t.count) }] }); });

🚀 部署与优化建议

方面

建议

高并发

Nginx反向代理 + Gunicorn/Uvicorn多worker

防重复提交

Redis分布式锁(创建短链接时)

恶意攻击

IP限流(FastAPI middleware + Redis计数器)

二维码美化

使用qrcode.image.svgmyqr添加logo

自定义短码

允许用户自定义(需校验唯一性)

批量生成

支持CSV导入,异步处理

http://www.jsqmd.com/news/1356263/

相关文章:

  • 商家自动化任务自动分析短信重要事情源码2-东方仙盟
  • Ohook:3分钟解锁Microsoft 365完整功能的技术方案
  • 济南网站建设艮安:从初创到腾飞,我们如何用代码与诚意重塑中小企业数字生命力
  • 2026 年当下,涿鹿专业的1250KVA变压器定做厂家推荐几家,车间深夜跳闸的幕后真凶,居然是这台不起眼的大家伙?-中能变压器 - 企业信息推荐-2
  • 2026年模架优质厂家推荐 宁海县美圆模架靠谱吗 - 起跑123
  • Agent与chain的调用工具的区别
  • 2026 年新消息:珠海口碑好的三氟氯乙烯制造商推荐,这种没人在意的化工原料,竟成高端制造业隐形刚需。 - 行业推荐官【认证】
  • dbt+SQLServer构建数据仓库(6):Jinja与DAG实战
  • 2026年物流周转车优质厂家推荐 法特五金产品测评 - 起跑123
  • 3天掌握BlenderGIS:从零到精通的地理数据三维可视化终极指南
  • 2026年近期信誉好的示教推车制造商推荐,实训教学数字化升级优选方案 - 装修教育财税推荐2026
  • 2026年宁波净化工程合作服务商选择指南分享 - 起跑123
  • 自制工业噪音音频素材的工程化应用与混音指南
  • Unity Input System虚拟摇杆开发:5分钟实现力反馈与动态摇杆
  • 2023年长春理工大学考研难度较低的专业 - 学工系统|学工平台|学生管理系统|学生信息管理系统|学工管理平台|智慧学工|智慧学工系统
  • 2026 年现阶段,阜南有实力的数控双面铣床供应厂家哪家**,车间里这款“两面手”,居然能帮厂家省下近三成的加工时间?-亿卓机械制造 - 行业严选官
  • 2026 年甘州销量好的边坡防护网施工厂商选哪家,山里的边坡垮塌竟因一个小细节?你不知道的施工隐患藏在这里。 - 企业推荐官-
  • 2026年找靠谱手推周转车厂家 不妨了解宁波法特五金工贸 - 起跑123
  • 2024年厦门市第31届小学生C++信息学竞赛试题与解析(第一部分选择题11-20)
  • 2026年选非标模架哪个厂家好 宁海县美圆模架有限公司 - 起跑123
  • 如何用GetQzonehistory找回那些被遗忘的QQ空间记忆?
  • 2026年浙江选购电源线插头,宁波仲基电线给你靠谱参考 - 起跑123
  • 2026主流AI PPT横向测评:效率内容与实用性客观对比
  • 2026 年更新:刚察性价比高的小区护栏网工厂找哪家,小区里的这圈铁网,居然藏着关乎全家安全的细节?-凯澈丝网 - 品质体验官
  • Unity Linux中文输入法兼容性解决方案:基于NPinyin的自制输入法实现
  • 2026年优选盐湖区毛坯房装修公司全案指南 - 装修教育财税推荐2026
  • 如何专业管理Windows驱动存储:DriverStore Explorer实战指南
  • 2026 年当下,松北靠谱的卧式鲜肉切片机源头厂家哪家可靠,切鲜肉居然能这么省人力?揭秘那台藏在后厨里的神器 - 实业推荐官
  • 2026年实测:8大宁波周末数学小升初机构综合评测
  • 2026年最新教程:自己怎么做拼豆图纸 亲测好用的免费方法 - 软件测评小帮手