阅读 419

【记录】赶鸭子上架的全栈开发踩坑思考

完全赶鸭子上架的全栈开发之旅,过程可以说是很崩溃,做完回顾发现留坑过多,痛定思痛还是要重新整理一下代码结构,复盘整个项目搞清楚到底菜在哪里,下面是此次开发过程中的一些具体问题的总结。

项目概述

项目名称:数据分析工具化
项目描述:excel表上传数据,系统提供模块化的结论

前端

框架选用:vue+vuex+vue-router
UI框架:element-ui

1. 关于在前台页面处理数据

初步考虑:一开始采用的方案是前台处理excel数据然后post数据到后台存储,主要考量有二,一是去除上传文件这一步骤,简化实现;二是前台对数据表格式进行校验,如果有错误可直接返回,减少不必要的带宽消耗。通过webworker也可以避免浏览器假死。
实际问题:低估了数据量级,实际拿到的excel表甚至超过了10MB,部分sheet甚至达到了百万条数据,浏览器的处理能力和内存有限,出现了out of memory错误。
解决方案:将这一步骤移交给后台处理

2. 关于vue-router的使用

初步考虑:PC站点不可避免的有站内导航和跳转,另一方面为了提升体验,页面缓存也是需要的,综上考虑引入了vue-router。

  • 实际问题01:贪图方便全员keepAlive了,导致页面缓存多了卡顿,懒惰是原罪
    解决方案:去除不必要的keepAlive
    // router配置
    { 
        path: '/upload',
        name: 'upload',
        component: DataUpload,
        meta: {
            keepAlive: true // 需要被缓存
        }
    },
    {
        path: '/export',
        name: 'export',
        component: ReportExport,
        meta: {
            keepAlive: false // 不需要被缓存
        }
    }
    
    // 引入页面
    <keep-alive>
        <router-view v-if="$route.meta.keepAlive" />
    </keep-alive>
    <router-view v-if="!$route.meta.keepAlive"/>
    复制代码
  • 实际问题02:需要新开页面展示某些信息
    解决方案:由于信息量级小,所以最终通过url带参的方式实现,router页面跳转
    // 新开页面
    router.resolve({
        name: "show-report-only",
        query: {
            url: url,
            name: name 
        }
    });
    window.open(href, '_blank');
    
    // 另一种带参跳转(不能新开页面)
    router.push({ name: 'user', params: { userId: '123' }}) // 参数存储在内存中,不在url显示
    复制代码

3. 关于vuex的使用

初步考虑:前期考虑不足,典型的我坑我自己。现在就是后悔,非常后悔。
实际问题:vuex是在项目进行到一定程度之后才加进去的,整个项目组件之间存在很多的共享信息,包括基础分析数据/页面状态等,当代码量级上去之后,简单的组件之间传值已经无法维持数据共享,而且组件之间的依赖过强,代码可读性严重下降。
解决方案:加入vuex来留存全局的状态信息。

4. 多复用操作的实现:Vue.directive指令

实际问题:在实际的实现场景下,有一些功能是基本所有组件都会使用到的,比如说都存在一个按钮,点击之后需要进行一系列类似的操作,这个时候就需要自定义指令上场,避免成为ctrlC/ctrlV工程师。
解决方案:加入自定义指令,统一管理类似的功能,提升可复用性,降低后期修改成本。

后端

框架选用:express
代理服务器:nginx

0. 关于框架选择的思考

在做这个项目之前没有正儿八经的用nodejs做后台开发,倒是之前在校期间,用过java和PHP,大概的思路是有的。基于这个前提下,还是保守的选用全家桶型框架express,使用之后感觉确实挺全的,但是有许多功能在实际使用中并不需要,后续考虑迁移到koa瘦个身。

1. post大数据超时

实际问题:后端最“重”的一个功能就是存数据,正如前端存excel表数据遇到的问题,将excel表上传到后端处理也有类似的问题,数据量过大,处理完成之后还要将几百万条数据存进数据库,容易造成超时,502/504错误。
解决方案:首选优化sql语句,加速处理;目前的快速解决方法是将express的socket连接超时时间。

server.on('connection', function (socket) {
    socket.setTimeout(30 * 1000);  // 超时时间,此处为30s
})
复制代码

后续优化:将接口拆分为2个接口异步操作,一个用于执行处理数据,另一个接口用于获取处理进度。

2. 涉及文件云存储

前期疏漏:前期很理所当然的将文件存储在了服务器本地,实际上对于需要长期存储的数据应当有专门的文件服务器来存储,后端逻辑与存储空间应当隔离。
解决方案:使用公司内部的oss存储,该接口必须线上调用,本地调用可能失败或响应时间过长。

3. CORS问题

实际问题:对于附带身份凭证的请求,服务器端设置Access-Control-Allow-Origin*无效
解决方案res.header('Access-Control-Allow-Origin', req.header('origin'));

4. 关于Docker

作为一个菜鸟完全不知道docker是什么东西怎么用,此次部署是傻瓜式操作,完全是大佬写好的配置文件,直接走平台部署。不懂就要学,后续找个时间实践一下,目前了解仅限于Docker类似于虚拟机的概念,但是Docker虚拟的是操作系统,它将同一个操作系统上管理的应用隔离开来,可以快速的创建和停止应用,不同应用之间互不影响。

数据库

mysql

1. 纯SQL语句与ORM库

实际问题:我肯定是脑子瓦特了,才会手写SQL,是框架不够好用还是加班不够久?
后续改进:为了后续项目能够更好兼容推进,改用ORM库来重构代码。

2. 数据库结构设计领悟

数据库真的是一门走一步要看三步的活计,前期设计作死在后面都是要还的。这一次设计过程中,又由于需求频繁变动,导致数据库修改避无可避,产生了一些非专业的感悟:

  • 慎用自增ID,尤其是对于需要更新的数据,对于一些无法用单一字段作为primary key的表,可以考虑多个字段通过md5之类的加密算法,生成唯一的ID作为primary key
  • 在前期需求不明朗,或者说项目最开始设计的时候,字段最好不要做过多的限制,比如说枚举类型,可以用tinyint来替代,后续如果有增减也不需要修改。
  • 前期慎重使用uniqueforeign key之类的限制性功能,后期需求谁也说不准,很容易翻车。另外如外键之类的功能也降低了数据添加的可控性。
  • 避免或尽量减少对一些较为特殊的内置字段类型/内置方法的使用,比如mysql的enum类型可以用varchar类型代替,timestamp类型可以用bigint存储时间戳代替,主要是考虑后续可能需要对多种数据库进行兼容。
关注下面的标签,发现更多相似文章
评论