
一、前言
在实际业务开发中,会遇到这样一种需求,使用VUE的页面需要支持SEO,同时对首屏有指标性要求,目前市面上普遍使用的是Nuxt.js解决方案,在引入的同时还需要考虑与现有的全栈工程结合,本系列文章探讨的是此类全栈工程的解决方案,同时使用的是TypeScript应用于前后端编程,文章中介绍的工程与技术要点源码已上传至Github,有需要的朋友可自行下载:
Nuxt.js和Nest.js同构工程
文章意在抛砖引玉,前后端使用同一种语言TypeScript编写,示例已包含基本接口请求,数据库连接应用,公用模块封装等实际开发中使用到的内容。
效果预览:

TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 一、《简介》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 二、《框架融合》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 三、《配置服务》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 四、《UI系统》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 五、《API服务设计》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 六、《SEO功能实现》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 七、《Vuex使用》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 八、《接入Mongo DB服务》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 九、《TypeScript》
TypeScript全栈工程实战-(Nuxt. js & Nest. js) - 十、《工程化部署》
二、MongoDB简介
- MongoDB

- MongoDB与Nest.js
开始之前先介绍MongoDB 的适用场景:
1.网站实时数据:实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
2.数据缓存:适合作为信息基础设施的缓存层。在系统重启之后,由MongoDB搭建的持久化缓存层可以避免下层的数据源过载。
3.大尺寸、低价值数据存储
4.高伸缩性场景:适合由数十或数百台服务器组成的数据库。
5.对象或JSON 数据存储: MongoDB 的BSON数据格式非常适合文档化格式的存储及查询。凭这一点,适合与Node.js集成。
6.Nest.js中使用
Nest.js有两种处理MongoDB数据库的方法。提供MongoDB支持的ORM,也可以使用最受欢迎的MongoDB对象建模工具Mongoose。如果想使用ORM,可以结合Type-ORM。本文中我们探讨的则为MongooseJS
三、连接MongoDB
-
建立本地MongoDB服务
参考官网安装配置 Install MongoDB ,注意设置的账号和密码,最终在 Robo 3T 可视化管理工具 中显示效果如下:
在本示例中,分别创建了 购物车、产品、用户等文结构。 -
独立配置
前文提到,本示例使用了前后端一体化配置,但特例情况是,对于数据库等敏感配置内容,不适合前后端共用,所以在本示例中,需要将其单独抽离。 依据环境变量,获取不同的配置 代码里边单独引用 -
建立连接
Nest.js使用MongoDB,默认集成Mongoose, 在使用时通过import的方式引入。 以示例中的本地模块为例:
1.建立LocalModule,LocalModule再导入DataBaseModule 2.DataBaseModule中通过provider和exports提供并导出公共服务
3.在Provider中则进行MongoDB连接。
至此,Nest.js中连接步骤完成。
四、效果
交互:
在首页中,绑定数据库中用户拥有的购物车产品数量,当点击【我的购物车】时,跳转至【购物车】页面,用户点击+或者-进行购物车物品数量增减操作,同时借助Vuex系统,进行多页面状态共享,最后更新至数据库中的【isomorphism.carts】文档中的num字段中进行数据持久化。

五、接口设计
-
文档设计
本示例中,从上图效果图来看用户首页显示当前购物车数量,点击进入可修改购物车数量。抽象成数据库表现为:
需要有一个文档,用于存放用户信息。
需要有一个文档,用于存放用户购物车信息,购物车信息由用户,用户存放的物品ID,每个物品在购物车中的数量构成。
需要有一个文档,用于存放商品原始SKU信息。
交互形式为:
用户界面中操作购物车数量,依据用户ID和产品ID将更新结果存放于存放用户购物车数量信息的文档中。 -
控制器实现
这里以更新购物车为例,截取部份代码片断,基础思路是使用POST接口,接收前端传入参数,再传入SERVICE服务层,同时接口层对传入和返回处理作统一的封装。
1.定义接口:
使用@Post('xxx')定义访问接口,Post为RESTful关键方法之一。@Body()获取传入参数。 2.定义入参结构
@Body()获取传入参可对传入参数进行强类型定义,Nest.js在处理参数功能上,作了自动字段校验,举个例子:本示例参数中的AddCartsDto
,那么框架层面将会对参数进行完整性校验,即按类型定义的内容,传少参数将会有接口错误信息抛出。 3.返回结构父类封装
- 返回结构定义
返回结构,这里将其定义为,需要一个方法,统一返所需要的结构,在Controller层调用时直接进行返回结果转换。 - 返回结构实现
新建父类,用于实现返回的两种结构,列表与普通对象,不管是哪一种结构,都会在上一层加上code
,message
,success
用于标识接口状态码,成功或失败字符串描述,接口成功与否状态。 - 子类继承
让Controller
子类继承自父类,这样子便拥用返回结构的两种方法,进行代码复用。
4.服务实现
在服务层,同样遵循与Controller
相同的机制,这里基础的增删改查,如果不是因特殊需求,是可以归纳封装在父类实现的。-
遵循Mongoose调用,在构造体中加入注册用到的文档Model结构:
-
Model结构需要在Provider中建立联接。
-
Schema结构。
这里的collection
建立与实体文档isomorphism.cats
的连接。
5.自定义功能实现
以依据ID获取已添加入购物车的列表数据项
为例,model负责实际的MongoDB语句操作,整个过程都是异步的,所以需要使用async
语句操作遵循所有moongoose语法规范:
- 返回结构定义
六、接口调用
服务端完成相关功能后,客户端则需要建立相关的单独服务类调用来承接该功能,例如本示例中的LocalService
:




七、延伸
-
登录功能
以上实现的是业务当中功能实现,在现实中,往往需要加上权限验证功能。这里作了一下简单示例实现。即
1.用户登录,存取TOKEN
2.每次请求时头部带上TOKEN信息
3.服务端进行合法性校验。
当然,与JAVA服务端等交互时可能会引入JWT等框架机制实现,在此不另作讨论 -
客户端登录
用户登录时需要对密码进行安全性保护,这里的做法是,使用MD5进行加密,到了服务端,再依据用户名,从DB中取出相应的HASH值校验。避免密码明文传输
。 如果校验通过,将返回用户信息,否则为空,并提示相关错误信息。 以上步骤完成,在服务端需要存储该用户登录信息到全局或者REDIS结构中。这里另外需要提一点,就是存入的REDIS或者客户端中的COOKIE应该有时间效性控制,即多久失效和过期。 -
统一拦截器
登录完成之后,需要拦截器中统一处理登录合法性校验,避免在各个业务逻辑中重复使用相同代码。在这里统一放至middleware
中进行处理。
1.服务端拦截
在业务中依据头部传入内容,检测用户合法性,不合法情况下返回错误信息。 2.客户端拦截
客户端则检测COOKIE中的登录信息是否存在,不存在则跳转至登录页面。