这是我参与「第三届青训营 -后端场」笔记创作活动的的第5篇笔记。
一、项目简介
极简版抖音的后端实现。极简抖音app提供的接口全部实现,包括用户注册、登录,关注、关注列表,视频流、发布视频,对视频点赞和评论等功能。
我们的Github地址,欢迎围观:github.com/JudyMu01/ea…
二、涉及技术&知识点
语言方面,本项目完全使用Golang完成,网络部分调用Gin框架,数据库用Gorm进行操作。数据库使用MySQL。外部依赖使用ffmpeg程序在视频上传时生成封面,并调用了github.com/u2takey/ffmpeg-go 库,可以在 go 语言端使用 ffmpeg 命令行工具。运用jwt-go生成、验证和保护客户端token。
三、实践过程
(1)数据库设计模型图
- user存储用户信息,含有user_id, username, password, create_time, modify_time。其中password为加密后的字符串。
- video存储视频信息,含有video_id, play_url, cover_url, title, create_time, user_id。其中user_id作为外键连接user和video,由于user和video存在一对多的关系。视频地址和封面地址均为服务器端静态地址,上传和读取都在服务器本机本项目的public文件夹里。
- comment存储评论信息,含有comment_id, user_id, content, create_time, video_id。其中video_id作为外键连接video和comment,由于video和comment存在一对多的关系。
- follow存储关注信息,user_id和to_user_id共同作为唯一决定关注信息的主键,外加一个create_time,用来给关注列表和粉丝列表排序。
- like存储点赞视频,user_id 和 video_id作为共同的主键,外加一个create_time用来排序。
(2)总体架构
其中,controller层为网络请求处理层,在客户端发送请求后,由router调用不同的controller层函数进行get或post操作,然后controller层会发回response。
service层用来处理controller层函数的具体操作,进行一些返回结构体的制作,或者调用数据库层的函数,并能处理一些异常。
repository层就是对数据库的一些增删改查操作啦。服务端启动的时候会自动初始化数据库,然后获取用户登录信息。
(3)项目亮点✨
服务性能
语言方面的性能优化
(1)slice预分配内存:尽量在使用make初始化切片时提供容量信息,避免内存反复分配。
var videoData = make([]VideoData, 20)
videoData, err = prepare_videoData(videos, token)
(2)map预分配内存:同理。初始化时写上size,避免内存反复分配。应用于:用户信息会在启动server时存到内存里,后续登录和退出登录操作不需要多次访问数据库。新用户注册时用户信息刷新。
工程中的性能优化
在青训营的课程中我们学到了,go语言本身支持高并发,以及各种消息队列,分布式对象存储的知识,能够利用削峰,解耦,异步的方法处理大量请求。然而,由于现阶段水平有限,时间有限,我并没有对新学到的这些知识进行实践,只是进行了一些调查和学习。
采用消息队列(待实现)
对象存储(待实现)
申请域名,项目上线(待实现)
安全可靠
- 密码存储用MD5算法加密。将用户在注册和登录时键入的密码转换成加密字符串,再生成token或进行数据库的操作,全程不在服务器端和数据库内明文展示用户密码信息。
- 本项目使用Gorm作为orm框架。在 Gorm 中,就为我们封装了 SQL 预编译技术。操作数据库时使用诸如此类的语句,当执行时user_id和 查询的数据id将被分开传输至数据库后端进行处理,从而防止SQL注入。
var user User
err := db.Where("user_id = ?", id).Find(&user).Error
- jwt-go鉴权
和token有点类似,在服务端加入了一个secret密钥,由用户发送用户名密码给服务端,服务端验证,成功之后就生成三个部分header,payload,signature组成的jwt token给客户端,之后的请求都带上 jwt token,服务端通过secret密钥进行验证。我们使用的第三方库是github.com/dgrijalva/jwt-go。
这一部分代码放在middleware包里,有两个文件,一个是auth.go,里面存了router会调用的那个handler,然后另一个是jwt.go,它调用第三方库,有两个函数,生成和解析token字符串,这个字符串里含有username,password,和expire_date三种信息。这样在客户端存储的token是加密过的,更加安全,而发回服务端后可以验证token是否过期,验证通过然后再进行用户想要的操作,否则返回错误,需要用户重新进行登录操作。
四、总结思考
其实对我们实现的这部分功能来说,没有什么特别的技术上的难点。硬要说的话,那些项目亮点都是难点。那么就说点心里话。
难点只是在于一直在运用新学到的东西。首先是go语言的编程,然后是gin,gorm框架,中间件我也是第一次接触,去配置路由,去写jwt的鉴权。在实践中,才慢慢摸清自己在做什么。
难点更是在于这个项目没有实现的那些优化功能,因为对我来说确实有点难,所以并没有在学期中花更多的时间去实现。
难点还在于,我第一次当组长,就经历了组员的各种退出,大家无一例外不是由于更大的目标而放弃这个项目,有的人为了全心全意准备实习推出,有的人因为大二课业繁忙而退出。一个人写项目,一直是很坚定的想要学到的东西的决心在支撑我做完这个项目,感谢青训营,感谢自己。
五、引用参考
Go截取视频某一帧图片 参考了这位大佬的做法。overstarry.vip/posts/go%E6…