一次TypeScript, React, Node, MongoDB的模板式前后端分离开发实践
前言
在大概1年前接触了typescript之后, 日渐被它所吸引. 甚至一个简单的本地测试文件node ./test.js
有时也会切到ts-node ./test.ts
. 在同样的时间节点之前, 还是会不时地去学学node, mongodb相关的. 可是, 由于懒(需)惰(求), 在很久没碰之后, 很多知识点都忘了!?
综上, 于是就有了今天这个话题:
论 如何在工作时间之余完成自己的个人项目并实现按时上床睡觉
答案是: 不存在的?
项目简介
项目会不断维护. 无论是client端还是server端, 都只提供简单的模板式的功能.
地址
client ts-react-webpack
server showcase
线上体验
依赖
typescript是两端的基调
client
- webpack-4.x
- typescript-3.0.x
- react-16.4.x
- mobx-5.x
- ant design
- ...
详看
server
centos上mongodb的官网安装教程, 其他系统请自行查阅.
- nestjs
- dotenv
- jsonwebtoken
- mongodb(mongoose)
- ...
需要讲一下我为什么选了nestjs:
nestjs
将typeScript
引入并基于express
封装. 意味着, 它与绝大部分express
插件的兼容性都很好.
nestjs
的核心概念是提供一种体系结构, 它帮助开发人员实现层的最大分离, 并在应用程序中增加抽象.
此外, 它对测试是非常友好的...
也需要声明的是, nestjs
的依赖注入特性是受到了angular
框架的启发, 相信做angular
开发的对整个程序体系会更容易看懂.
查看中文文档
具体实现
server
简单介绍下几个主流程模块
main.ts
我是用nest-cli工具初始化项目的, 一切从src/main.ts
开始
import { NestFactory } from '@nestjs/core'
import * as dotenv from 'dotenv'
import { DOTENV_PATH } from 'config'// 优先执行, 避免引用项目模块时获取环境变量失败
dotenv.config({ path: DOTENV_PATH })import { AppModule } from './app.module'async function bootstrap() {const app = await NestFactory.create(AppModule)// 支持跨域app.enableCors()await app.listen(9999)
}
bootstrap()
复制代码
同样地, 我们可以提供一个express
实例到NestFactory.create
:
const server = express();
const app = await NestFactory.create(ApplicationModule, server);
复制代码
这样我们就可以完全控制express
实例生命周期, 比如官方FAQ中说到的创建几个同时运行的服务器
在我本地开发的时候, 根目录上还有一个.dev.env
, 这是未提交到github的, 因为里面包含了我个人的mongodb
远程ip
地址 其他内容与github上的.env
一致, 因为我本地并不想再安装一遍mongodb
, 如果是想把项目拉下来就跑起来的, 无论如何你都需要一个mongodb
服务, 当然你是可以本地安装就好了.
还需要提及到一点就是调试:
以前在vscode上调试node程序都需要在调试栏新增配置, 然后利用该配置去跑起应用才能实现断点调试, 新版的vscode支持autoAttach功能, 使用Command
+ Shift
+ P
唤起设置功能面板
启动它!
这样, 在项目的.vscode/setting.json
里面会多了一个选项: "debug.node.autoAttach": "on"
, 在我们的启动script里面加上--inspect-brk
就可以实现vscode的断点调试了. 对应地, npm run start:debug
是我的启动项, 可参考nodemon.debug.json
app.module.ts
import { Module } from '@nestjs/common'
import { MongooseModule } from '@nestjs/mongoose'import { DB_CONN } from 'config/db'
import { AppController } from './app.controller'
import { AppService } from './app.service'
import modules from 'routers'@Module({imports: [MongooseModule.forRoot(DB_CONN, {useNewUrlParser: true,}),...modules,],controllers: [AppController],providers: [AppService],
})
export class AppModule {}
复制代码
每个 Nest 应用程序至少有一个模块, 即根模块. 根模块是 Nest 开始安排应用程序树的地方. 事实上, 根模块可能是应用程序中唯一的模块, 特别是当应用程序很小时, 但是对于大型程序来说这是没有意义的. 在大多数情况下, 您将拥有多个模块, 每个模块都有一组紧密相关的功能. 当然, 模块间也可以共享.
概念 | 解释 |
---|---|
providers |
由Nest 注入器实例化的提供者,并且可以至少在整个模块中共享
|
controllers | 必须创建的一组控制器 |
imports | 导入模块所需的导入模块列表 |
exports | 此模块提供的提供者的子集, 并应在其他模块中使用 |
参考module
的文档
AppController
在这个程序当中只是为了测试能返回Hello World!!!
, 其实它不是必须的, 我们可以把它直接干掉, 把全部接口, 全部逻辑放到各个module
中实现, 以modules/user
为例, 接着往下看.
modules/user
目录结构
user
├── dto -------------- 数据传输对象
├── index.ts --------- UserModule, 概念同AppModule
├── controller.ts ---- 传统意义的控制器, `Nest`会将控制器映射到相应的路由
├── interface.ts ----- 类型声明
├── schema.ts -------- mongoose schema
├── service.ts ------- 处理逻辑
复制代码
有必要讲讲controller.ts
和service.ts
, 这是nestjs的概念中很重要的部分
controller.ts
import { Get, Post, Body, Controller } from '@nestjs/common'import UserService from './service'
import CreateDto from './dto/create.dto'@Controller('user')
export default class UserController {constructor(private readonly userService: UserService) {}@Get()findAll() {return this.userService.findAll()}@Post('create')create(@Body() req: CreateDto) {return this.userService.create(req)}
}
复制代码
装饰器路由为每个路由声明了前缀,所以Nest
会在这里映射每个/user
的请求
@Get()
装饰器告诉Nest
创建此路由路径的端点
同样地, @Post()
也是如此, 并且这类Method装饰器接收一个path
参数, 如@Post('create')
, 那么我们就可以实现post到路径/user/create
到此, 往后的逻辑交给service
实现
service.ts
import { Injectable } from '@nestjs/common'
import { InjectModel } from '@nestjs/mongoose'
import { Model } from 'mongoose'import logger from 'utils/logger'
import { cryptData } from 'utils/common'
import ServiceExt from 'utils/serviceExt'
import { IUser } from './interface'
import CreateDto from './dto/create.dto'@Injectable()
export default class UserService extends ServiceExt {constructor(@InjectModel('User') private readonly userModel: Model<IUser>) {super()}async create(createDto: CreateDto) {if (!createDto || !createDto.account || !createDto.password) {logger.error(createDto)return this.createResData(null, '参数错误!', 1)}const isUserExist = await this.isDocumentExist(this.userModel, {account: createDto.account,})if (isUserExist) {return this.createResData(null, '用户已存在!', 1)}const createdUser = new this.userModel({...createDto,password: cryptData(createDto.password),})const user = await createdUser.save()return this.createResData(user)}async findUserByAccount(account: string) {const user = await this.userModel.findOne({ account })return user}async findAll() {const users = await this.userModel.find({})return this.createResData(users)}
}复制代码
至此, 我们运行npm run start:dev
启动一下服务:
直接在浏览器端访问http://localhost:9999/#/
没错, 的确失败了!!! 因为我们使用了jsonwebtoken
, 在modules/auth
可以看到它的实现.
现在我们在postman
中登录了再试试吧!
bingo!!!
(如果是想拉下来跑的话, 也可以照着schema
的格式用postman
先伪造条用户数据, 把系统打通!!!)
client
关于client端的实现我不会细讲, 可以看项目github, 和我之前的文章(typescript-react-webpack4 起手与踩坑), 项目结构会有改动.
讲一下接入了真实服务器之后http请求对于token的一些处理, 查看http.ts
首先是创建axios
实例时需要在header
处把token带上
const axiosConfig: AxiosRequestConfig = {method: v,url,baseURL: baseUrl || DEFAULTCONFIG.baseURL,headers: { Authorization: `Bearer ${getCookie(COOKIE_KEYS.TOKEN)}` }
}
const instance = axios.create(DEFAULTCONFIG)
复制代码
token也可以存放在localStorage
另外一点是, 对应服务端返回的token错误处理
const TOKENERROR = [401, 402, 403]
let authTimer: number = null
...if (TOKENERROR.includes(error.response.status)) {message.destroy()message.error('用户认证失败! 请登录重试...')window.clearTimeout(authTimer)authTimer = window.setTimeout(() => {location.replace('/#/login')}, 300)return
}
复制代码
总结
两端项目都是简单的模板项目, 不存在什么繁杂的业务, 属于比较初级的学习实践. 对nestjs
的掌握程度有限, 只是拿来练练手. 可能后续会基于这篇文章继续深入地去讲讲, 比如部署之类的, 两个项目也会不断去维护. 后续也有计划会合二为一. 看时间吧!
一次TypeScript, React, Node, MongoDB的模板式前后端分离开发实践相关推荐
- Node.js + Express + Springboot实现前后端分离架构
2019独角兽企业重金招聘Python工程师标准>>> 架构说明 前后端分离架构,很多团队都是通过"代理转发"浏览器发往后端的rest请求来解决跨域问题,可以用n ...
- node、Mongo项目如何前后端分离提供接口给前端
node接口编写,vue-cli代理接口方法 通常前端使用的MocK 数据的方法,去模拟假的数据,但是如果有node Mongodb 去写数据的话就不需要在去mock 数据了,具体的方法如下. 首先 ...
- node vue 合并项目_吐血整理最佳实践:SpringBoot整合Vue前后端分离开发
[toc] 开发环境 IDEA V2018.5 npm v6.4.x vue-cli v2.9.x 创建项目 IDEA > Create New Project > Gradle 2018 ...
- 基于node.js和vue的前后端分离影院售票系统电影院影片管理
1,项目介绍 基于 node.js和vue 的影院售票系统拥有两种角色,分别为管理员和用户. 用户:热映.即将上映.电影和影院全局搜索.评论.选座.购票.点赞.收藏.订单等一系列购票功能 管理员:用户 ...
- Node — 第六天(前后端分离)及(身份验证)
综合应用服务端知识点搭建项目 下载安装所需的第三方模块 npm init -y npm i express cors mysql # express 用于搭建服务器 # cors 用于解决跨域 # m ...
- 阿里云轻量应用服务器部署Node.js+React+MongoDB前后端分离项目
最近用阿里云服务器部署了一个前端React,后端Node.js(Koa2),数据库MongoDB的前后端分离项目,其间踩了不少的坑,用这篇文章记录一下具体的步骤,希望对你们能有帮助. 1. 服务器的选 ...
- 图解基于 Node.js 实现前后端分离 - CSDN博客
因为会上出了个意外,ppt图片全部丢失,只好对着白板跟大家交流了半个多小时.由于我做演讲不喜欢写太多的文字,没有图片的情况下讲漏了一些内容.这篇文章是我在会上分享内容对照ppt进行地整理. 基本介绍 ...
- 图解基于node.js实现前后端分离
因为会上出了个意外,ppt图片全部丢失,只好对着白板跟大家交流了半个多小时.由于我做演讲不喜欢写太多的文字,没有图片的情况下讲漏了一些内容.这篇文章是我在会上分享内容对照ppt进行地整理. 基本介绍 ...
- 解答网友提问 | 使用VS2022快速生成React/Angular/Vue.js + Web API前后端集成项目
前言 上次发表了<一键生成Vue.js + Web API前后端集成项目>后,有多位网友来问,有不有其他的前后端集成模板: 实际上,VS2022没有提供前后端集成项目模板. 但是,使用VS ...
- php node.js django,Vue.js和Django搭建前后端分离项目示例详解
本篇文章主要介绍了Django+Vue.js搭建前后端分离项目的示例,具有一定参考价值,有兴趣的可以了解一下 在写这篇文章的时候,顺带学习了一下关于Markdown的使用方法. 笔者是个渣渣,一切都是 ...
最新文章
- Linux 自动重启进程
- LeetCode-35. Search Insert Position
- 【PAT甲级 - 1013】Battle Over Cities (25分)(并查集)
- 网页检测不到java无法打印_如果PC连接到网络打印机,如何检查java?
- Barebox for Tiny6410(LCD驱动移植)
- PHP 使用 ZipArchive 将文件打包成 zip
- hashcode值相同的字符串
- 【广东大学生网络攻防大赛-WriteUp(非官方)】Pwn | jmp_rsp
- sigmaplot画辐射方向图教程
- STM8S003引脚坑(开发过的人都知道)
- 博士生导师谈他如何检索文献
- 人工神经网络基本构成有哪些,具有什么特征
- 荣耀50和荣耀50se参数对比 哪个更值得入手
- POI获取单元格颜色与设置单元格颜色
- 新疆伊犁山开挖破裂机液压岩石劈裂棒 大型岩石分裂棒行业推荐
- 企业业务架构设计方法论及实践(二)
- 搭建开发环境 | 工欲善其事,必先利其器(C、C++、Java、Python)
- 微信公众号授权,支付,退款总结
- 【MyBatis】进一步理解choose、when、otherwise标签
- cloudreve win10 解析域名_Cloudreve 云盘直链获取源码