c站(clicli.us)3.0 重构经验分享
yisar opened this issue · 2 comments
halo,大家好,我是 132
唔,经过四天时间,c站的 3.0 重构终于告一段落啦
重构真的是,最不合算的重复劳动了
可是每次重构,都或多或少的,学到新东西
之前的 2.0 重构的文章,在这里:#147
重构背景
v2 版本一来,经过接近一年的时间,随着c站业务的发展,已经出现一些问题
比如我们的番剧系统,需要更加强大的索引
比如我们的 ugc 版权,需要更加合理的上传审核机制
等等
加上多人协作,代码质量每况愈下
本来是打算等到 vue3 发版再重构的来着,但是还是没能忍得住,就提前重构了
目标
- 对代码进行重新梳理,提高代码质量,减小维护成本
- 对各个端进行重构,更完美的服务业务,更有利于下次重构
开始
后端 API 重构
重构的开端还是从 API 开始
本次后端重构,最主要的是重构了番剧索引接口
场景主要就是,这种索引的场景,其中,分类、状态等,单选,标签多选,条件间取交集,标签取并集
其实这个场景在视频网站中非常多见,对于后端来说,是个一对多,多对多的问题
上个版本 c站 使用了 redis 来做这个逻辑
略复杂,这个版本,使用了更简单的方式,拼接字符串
var query string
if status != "" && status != "nowait" {
query = fmt.Sprintf(`AND posts.status ='%s'`, status)
}
if sort != "" {
query += fmt.Sprintf(`AND posts.sort ='%s'`, sort)
}
if uid != 0 {
query += fmt.Sprintf(`AND posts.uid ='%d'`, uid)
}
if status == "nowait" {
query += `AND NOT posts.status='wait'`
}
···
这样就会根据参数,拼成一个字符串
为了防止所有参数都没有的情况,可以默认携带一个 1=1
```sql
sqlRaw := fmt.Sprintf(`SELECT posts.id,posts.title,posts.content,posts.status,posts.sort,posts.tag,posts.time,users.id,users.name,users.qq FROM posts LEFT JOIN users ON posts.uid = users.id
WHERE 1=1 %s ORDER BY time DESC`, query)
这样就可以做成一个完美的查询接口啦,一个接口搞定一切查询的 case
接口预览:https://api.clicli.us/posts?status=public&sort=新番&tag=推荐+耽美&uid=2&page=1&pageSize=10
然后对于用户接口等,同时也做了类似的调整
然后后端就没啥啦
前端
前端的重构,其实就是重新写了 API,大概提几个要点吧
###. 跨域
跨域是个很尴尬的问题,之前面试还一直被问,我当时是咋说的来着?
不解释,就是反代
这次最坑的是,我真的是,三天重构时间,因为我没有去反代,浪费了一天时间
最主要的是非简单请求的 options携带 cookie 的问题
据说,需要同时满足两个条件:
withcredentials必须设置为true, origin不能用通配符*
可惜,捣鼓了好久,还是不能很好的解决
最终我很后悔这次尝试,我从一开始就应该坚定立场
面试官你再敢问,我就不解释,反代送给你
新番时间表
之前我们是后台手动设置,很不够傻瓜化
这次决定做成自动的
方法就是对数据的重新遍历
let ret = {
1: [],
2: [],
3: [],
4: [],
5: [],
6: [],
0: [],
}
res.data.posts.forEach(item => {
let day = new Date(item.time).getDay()
ret[day].push(item)
})
this.items = ret
ret 一个以数字为 key 的 对象,分别代表了周一到周日,0 为周日
然后渲染就很容易啦
<li v-for="item in items[activeIndex]">
<router-link :to="'/play/gv'+item.id">
<img :src="getSuo(item.content)" :alt="item.title">
<div class="text">
<div class="title">{{item.title}}</div>
</div>
</router-link>
</li>
activeIndex 就是今天的 getDay()
其实这种通过当前日期来自动归类数据的小技巧,还是经常用用
能缩减很多维护量的
标签
场景如图,就是标签的选择和去选择
通常,很多人喜欢用多选框来做,然后通过 label 去绑定样式等等
但是其实不用,因为无论怎么选择,最终对应的都是字符串而已
在此之前,先搞定,多个参数怎么在 url 里传递
GET /posts?tag=标签1+标签2
后端拿到的,其实是两个标签中间,有一个空格
标签1 标签2
也就是说,我们选择多少个标签,只需要用空格去追加字符串即可
selectTag(item) {
if (this.state.tag.includes(item)) {
this.setState({
tag: this.state.tag.replace(` ${item}`, '')
})
} else {
this.setState({
tag: this.state.tag + ` ${item}`
})
}
}
通过 includes ,包含这个字符串就高亮,再点击就是移除字符串,取消高亮
一个非常简单的标签功能就搞定了
然后,好像就没有然后了::>_<::
APP
app 是由 @jwchan1996 小哥哥负责更新的,我只是打辅助,不知道他会不会发文章呢::>_<::
然后我遇到了一个问题,就是版本发布的坑,我们每次发布,都没有好的版本控制
导致很多人下载不到最新的版本,也没办法上架应用商店
所以想了个办法,发布到 npm 上,每次就可以 @latest 啦,哈哈哈
总结
细细想来,这次重构确实,没什么新的东西
都怪我尿性使然,等不及 vue 3
不过等 vue3 发版,我们还会继续重构,到时候再来一波分享吧
链接
c站首页:https://clicli.us
c站原创页:https://clicli.us/explore
APP
永久最新下载地址:https://unpkg.com/@clicli/app
github 开源地址:https://github.com/acgzone
接口文档:https://github.com/acgzone/acgzone-server/wiki/API
??github 开源地址:https://github.com/acgzone 都是空的?