前言

在大概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:

nestjstypeScript引入并基于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.tsservice.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的模板式前后端分离开发实践相关推荐

  1. Node.js + Express + Springboot实现前后端分离架构

    2019独角兽企业重金招聘Python工程师标准>>> 架构说明 前后端分离架构,很多团队都是通过"代理转发"浏览器发往后端的rest请求来解决跨域问题,可以用n ...

  2. node、Mongo项目如何前后端分离提供接口给前端

    node接口编写,vue-cli代理接口方法  通常前端使用的MocK 数据的方法,去模拟假的数据,但是如果有node Mongodb 去写数据的话就不需要在去mock 数据了,具体的方法如下. 首先 ...

  3. node vue 合并项目_吐血整理最佳实践:SpringBoot整合Vue前后端分离开发

    [toc] 开发环境 IDEA V2018.5 npm v6.4.x vue-cli v2.9.x 创建项目 IDEA > Create New Project > Gradle 2018 ...

  4. 基于node.js和vue的前后端分离影院售票系统电影院影片管理

    1,项目介绍 基于 node.js和vue 的影院售票系统拥有两种角色,分别为管理员和用户. 用户:热映.即将上映.电影和影院全局搜索.评论.选座.购票.点赞.收藏.订单等一系列购票功能 管理员:用户 ...

  5. Node — 第六天(前后端分离)及(身份验证)

    综合应用服务端知识点搭建项目 下载安装所需的第三方模块 npm init -y npm i express cors mysql # express 用于搭建服务器 # cors 用于解决跨域 # m ...

  6. 阿里云轻量应用服务器部署Node.js+React+MongoDB前后端分离项目

    最近用阿里云服务器部署了一个前端React,后端Node.js(Koa2),数据库MongoDB的前后端分离项目,其间踩了不少的坑,用这篇文章记录一下具体的步骤,希望对你们能有帮助. 1. 服务器的选 ...

  7. 图解基于 Node.js 实现前后端分离 - CSDN博客

    因为会上出了个意外,ppt图片全部丢失,只好对着白板跟大家交流了半个多小时.由于我做演讲不喜欢写太多的文字,没有图片的情况下讲漏了一些内容.这篇文章是我在会上分享内容对照ppt进行地整理. 基本介绍 ...

  8. 图解基于node.js实现前后端分离

    因为会上出了个意外,ppt图片全部丢失,只好对着白板跟大家交流了半个多小时.由于我做演讲不喜欢写太多的文字,没有图片的情况下讲漏了一些内容.这篇文章是我在会上分享内容对照ppt进行地整理. 基本介绍 ...

  9. 解答网友提问 | 使用VS2022快速生成React/Angular/Vue.js + Web API前后端集成项目

    前言 上次发表了<一键生成Vue.js + Web API前后端集成项目>后,有多位网友来问,有不有其他的前后端集成模板: 实际上,VS2022没有提供前后端集成项目模板. 但是,使用VS ...

  10. php node.js django,Vue.js和Django搭建前后端分离项目示例详解

    本篇文章主要介绍了Django+Vue.js搭建前后端分离项目的示例,具有一定参考价值,有兴趣的可以了解一下 在写这篇文章的时候,顺带学习了一下关于Markdown的使用方法. 笔者是个渣渣,一切都是 ...

最新文章

  1. Linux 自动重启进程
  2. LeetCode-35. Search Insert Position
  3. 【PAT甲级 - 1013】Battle Over Cities (25分)(并查集)
  4. 网页检测不到java无法打印_如果PC连接到网络打印机,如何检查java?
  5. Barebox for Tiny6410(LCD驱动移植)
  6. PHP 使用 ZipArchive 将文件打包成 zip
  7. hashcode值相同的字符串
  8. 【广东大学生网络攻防大赛-WriteUp(非官方)】Pwn | jmp_rsp
  9. sigmaplot画辐射方向图教程
  10. STM8S003引脚坑(开发过的人都知道)
  11. 博士生导师谈他如何检索文献
  12. 人工神经网络基本构成有哪些,具有什么特征
  13. 荣耀50和荣耀50se参数对比 哪个更值得入手
  14. POI获取单元格颜色与设置单元格颜色
  15. 新疆伊犁山开挖破裂机液压岩石劈裂棒 大型岩石分裂棒行业推荐
  16. 企业业务架构设计方法论及实践(二)
  17. 搭建开发环境 | 工欲善其事,必先利其器(C、C++、Java、Python)
  18. 微信公众号授权,支付,退款总结
  19. 【MyBatis】进一步理解choose、when、otherwise标签
  20. cloudreve win10 解析域名_Cloudreve 云盘直链获取源码

热门文章

  1. iperf3怎么看结果_iperf3命令使用
  2. nodejs中md5加密模块
  3. java检查页面ajax请求,Java AJAX电子邮件检验示例
  4. go语言php编译,golang怎么编译
  5. C++编译器在编译程序时会自动定义的预处理器(类似于全局变量)
  6. 全网首发:JDK绘制文字:八、绘制函数简要分析
  7. 你不能强迫别人进步,跟别人没法强迫你进步一样
  8. 在龙芯机器上编译OpenJDK8
  9. LINUX SHELL脚本的if语句实在是诡异
  10. 百度人脸识别:功能开通