当前位置: 首页 > 后端技术 > Node.js

TypeScript、React、Node、MongoDB的模板式前后端分离开发实践

时间:2023-04-03 17:53:39 Node.js

前言大约1年前接触到typescript后,逐渐被它吸引。即使是一个简单的本地测试文件node./test.js有时也会切到ts-node./test.ts。在同一时间node之前,我还是会时不时的学习一下node和mongodb。但是,由于懒(需要)和懒(乞),好久没接触了,很多知识点都忘记了!?综上所述,于是就有了今天的话题:关于下班后如何完成自己的个人项目并按时睡觉,答案是:不存在?项目简介项目将持续维护。客户端和服务端都只提供简单的模板式功能。地址clientts-react-webpackservershowcase在线体验依赖typescript是两端的主旨clientwebpack-4.xtypescript-3.0.xreact-16.4.xmobx-5.xantdesign...详见mongodb官网在servercentos上的安装教程,其他系统请自行检查。nestjsdotenvjsonwebtokenmongodb(mongoose)...需要说一下为什么选择nestjs:nestjs引入了typeScript,并基于express进行了封装。这意味着它与大多数express插件非常兼容。nestjs的核心理念是提供一种架构,帮助开发者在应用中实现层的最大分离,增加抽象。另外,对测试非常友好。。。另外需要说明的是,nestjs的依赖注入特性是受到了angular框架的启发,相信这样做的话,理解整个程序体系会更容易角发育。服务端具体实现查看中文文档,简单介绍以下主要流程模块main.ts。我使用nest-cli工具初始化项目。EverythingStartfromsrc/main.tsimport{NestFactory}from'@nestjs/core'import*asdotenvfrom'dotenv'import{DOTENV_PATH}from'config'//先执行,避免引用项目模块时获取不到环境变量dotenv.配置({路径:DOTENV_PATH})导入{AppModule}来回m'./app.module'asyncfunctionbootstrap(){constapp=awaitNestFactory.create(AppModule)//支持跨域app.enableCors()awaitapp.listen(9999)}bootstrap()同理,我们可以为NestFactory.create提供一个express实例:constserver=express();constapp=awaitNestFactory.create(ApplicationModule,server);这样我们就可以完全控制expressinstance的生命周期,比如在官方FAQ中创建多个同时运行的server是在本地开发的,根目录下有一个.dev.env,没有提交到github,因为里面有我个人的mongodb远程ip地址,其他内容和github上的.env是一致的,因为不想在本地再安装mongodb。如果你想把项目拉下来运行,无论如何你都需要一个mongodb服务。当然,你也可以在本地安装。还有一点要提的是调试:在vscode上调试node程序之前,需要在调试栏中添加一个新的配置,然后使用这个配置来运行应用程序,实现断点调试。新版vscode支持autoAttach功能,使用Command+Shift+P调出设置功能面板即可启动!这样在项目的.vscode/setting.json中就会多出一个选项:"debug.node.autoAttach":"on",在我们的启动脚本中加入--inspect-brk,实现vscode断点调试。对应的,npmrunstart:debug是我的启动项,参考nodemon.debug.jsonapp.module.tsimport{Module}from'@nestjs/common'import{MongooseModule}from'@nestjs/mongoose'import{DB_CONN}from'config/db'导入{AppController}from'./app.controller'import{AppService}from'./app.service'从'routers'@Module({imports:[MongooseModule.forRoot(DB_CONN,{useNewUrlParser:true,}),...modules,],controllers:[AppController],providers:[AppService],})exportclassAppModule{}每个Nest应用至少有一个模块,即根模块。根模块是Nest开始安排应用树的地方。事实上,根模块可能是应用程序中唯一的模块,尤其是当应用程序很小的时候,但是对于大型程序来说这没有意义。大多数情况下,你会有多个模块,每个模块都有一组密切相关的功能。当然,模块也可以共享。这个概念解释了提供者由Nest注入器实例化,并且至少可以通过控制器必须创建的一组控制器导入在整个模块中共享。所需的导入模块列表导出了该模块提供的提供程序的一个子集,并且应该在其他模块中使用。请参阅模块的文档。AppController在本程序中只是为了测试它能返回HelloWorld!!!,其实没有必要,我们可以直接干掉它,把所有的接口和所有的逻辑放到每个模块中去实现,取modules/user举个例子,再往下看。modules/user目录结构user├──dto-------------数据传输对象├──index.ts--------UserModule,概念同上AppModule├──controller.ts----传统控制器,`Nest`将控制├──interface.ts-----类型声明├──schema.ts--------mongooseschema├──service.ts--------处理逻辑必须说说controller.ts和service.ts,这是nestjscontroller.tsimport{Get,Post,Body,Controller}from'@nestjs/common'的概念中很重要的一部分CreateDtofrom'./dto/create.dto'@Controller('user')exportdefaultclassUserController{constructor(privatereadonlyuserService:UserService){}@Get()findAll(){returnthis.userService.findAll()}@Post('create')create(@Body()req:CreateDto){returnthis.userService.create(req)}}装饰器路由为每个路由声明了一个前缀,所以Nest会在这里映射每个/user请求@Get()装饰器告诉Nest创建此路由路径的端点。同理,@Post()也是一样的,这类Method装饰器接收一个路径参数,比如@Post('create'),那么我们就可以在这里实现Post到路径/user/create,后面的逻辑是交给服务实现service.tsimport{Injectable}from'@nestjs/common'import{InjectModel}from'@nestjs/mongoose'import{Model}from'mongoose'importloggerfrom'utils/logger'import{cryptData}from'utils/common'importServiceExtfrom'utils/serviceExt'import{IUser}from'./interface'importCreateDtofrom'./dto/create.dto'@Injectable()exportdefaultclassUserServiceextendsServiceExt{constructor(@InjectModel('User')privatereadonlyuserModel:Model){super()}asynccreate(createDto:CreateDto){if(!createDto||!createDto.account||!createDto.password){logger.error(createDto)returnthis.createResData(null,'参数错误!',1)}constisUserExist=awaitthis.isDocumentExist(this.userModel,{account:createDto.account,})if(isUserExist){returnthis.createResData(null,'用户已经存在!',1)}constcreatedUser=newthis.userModel({...createDto,password:cryptData(createDto.password),})constuser=awaitcreatedUser.save()returnthis.createResData(user)}asyncfindUserByAccount(account:string){constuser=awaitthis.userModel.findOne({account})返回你ser}asyncfindAll(){constusers=awaitthis.userModel.find({})returnthis.createResData(users)}}至此,我们运行npmrunstart:dev启动服务:直接在浏览器访问httpside://localhost:9999/#/是的,确实失败了!!!因为我们使用了jsonwebtoken,大家可以在modules/auth中看到它的实现。现在我们登录邮递员再试一次!答对了!!!(如果想拉下来运行,也可以用postman根据schema的格式伪造一段用户数据通过系统打通!!!)具体实现我就不细说了client端,可以看项目github,还有我之前的文章(typescript-react-webpack4起步和踩坑),项目结构会有所改变。说一下连接到真实服务器后对token的http请求的一些处理。检查http.ts。首先,您需要在标头中创建一个axios实例PuttokenonconstaxiosConfig:AxiosRequestConfig={method:v,url,baseURL:baseUrl||DEFAULTCONFIG.baseURL,headers:{Authorization:`Bearer${getCookie(COOKIE_KEYS.TOKEN)}`}}constinstance=axios.create(DEFAULTCONFIG)token也可以存储在localStorage还有一点就是对应服务器返回的token的错误处理constTOKENERROR=[401,402,403]letauthTimer:number=null...if(TOKENERROR.includes(error.response.status)){message.destroy()message.error('用户认证失败!请登录后重试...')window.clearTimeout(authTimer)authTimer=window.setTimeout(()=>{location.replace('/#/login')},300)return}综上,两端的项目都是简单的模板项目,没有什么复杂的业务,属于比较初级的学习实践。nestjs的掌握程度有限,只是用来练习。可能我会在这篇文章的基础上继续深入讲,比如部署,两个项目会继续维护。也会有后续的Plans一起来。注意时间!