frontend9/fe9-library

c站(clicli.us)3.0 重构经验分享

yisar opened this issue · 2 comments

yisar commented

halo,大家好,我是 132
唔,经过四天时间,c站的 3.0 重构终于告一段落啦
QQ图片20190413181623

重构真的是,最不合算的重复劳动了
可是每次重构,都或多或少的,学到新东西

之前的 2.0 重构的文章,在这里:#147

重构背景

v2 版本一来,经过接近一年的时间,随着c站业务的发展,已经出现一些问题
比如我们的番剧系统,需要更加强大的索引
比如我们的 ugc 版权,需要更加合理的上传审核机制
等等
加上多人协作,代码质量每况愈下

本来是打算等到 vue3 发版再重构的来着,但是还是没能忍得住,就提前重构了

目标

  1. 对代码进行重新梳理,提高代码质量,减小维护成本
  2. 对各个端进行重构,更完美的服务业务,更有利于下次重构

开始

后端 API 重构

重构的开端还是从 API 开始
本次后端重构,最主要的是重构了番剧索引接口
image
场景主要就是,这种索引的场景,其中,分类、状态等,单选,标签多选,条件间取交集,标签取并集

其实这个场景在视频网站中非常多见,对于后端来说,是个一对多,多对多的问题
上个版本 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不能用通配符*

可惜,捣鼓了好久,还是不能很好的解决
最终我很后悔这次尝试,我从一开始就应该坚定立场

面试官你再敢问,我就不解释,反代送给你

新番时间表

QQ图片20190413202124
场景如图,需要一个从 周一到周日 的新番表

之前我们是后台手动设置,很不够傻瓜化

这次决定做成自动的
方法就是对数据的重新遍历

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()

其实这种通过当前日期来自动归类数据的小技巧,还是经常用用
能缩减很多维护量的

标签

QQ图片20190413202947
场景如图,就是标签的选择和去选择
通常,很多人喜欢用多选框来做,然后通过 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 都是空的?