快速搭建node.js新项目和大事件后台项目

news2024/10/6 14:38:50

声明:参考https://zhuanlan.zhihu.com/p/464271490?utm_id=0

参考:https://brucecai55520.gitee.io/bruceblog/notes/nodejs/ev_api_server.html#_1-4-%E5%88%9D%E5%A7%8B%E5%8C%96%E8%B7%AF%E7%94%B1%E7%9B%B8%E5%85%B3%E7%9A%84%E6%96%87%E4%BB%B6%E5%A4%B9

快速搭建node.js新项目?看这篇就够了!

问题:

  1. 你是否知道npm的概念和作用?
  2. 你是否知道模块化的概念,和node项目中的模块化?
  3. 搭建node新项目时,为实现某一基本功能,你是否总是在网上各种查找如何安装对应的模块包和相关配置

如果这些问题在你心中都有标准答案,那你就可以去看别的文章啦~

如果你还有些一知半解,欢迎看官们评阅我的文章!

前言

最近自己编写了一个后台管理系统,选用了 node.js 和 vue 相关框架和技术。也算是收获了不少知识和经验,因此,我来写下这篇文章,向大家分享一些关于node.js的核心知识,并在最后手把手教你们快速搭建并配置一个node新项目(涉及如何配置express、joi、jwt、mysql、cors)。

Node.js是什么?

首先,想必大家都使用过JavaScript吧!

你们知道为什么JavaScript可以操作浏览器中的DOM和BOM吗?

每个浏览器都内置了 DOM、BOM 这样的  API 函数,因此,浏览器中的 JavaScript 才可以调用它们。

那么,为什么浏览器可以解析JavaScript语言呢?

不同的浏览器使用了不同的  JavaScript 解析引擎,用来解析我们编写JavaScript
其中,Chrome 浏览器的  V8 解析引擎性能最好

这里我在网上找了张图片,很生动地解释了我上面的回答:

Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine.
Node.js 是一个基于  Chrome V8 引擎的  JavaScript 后端运行环境

简而言之,就是一个使用JavaScript写后端的一个技术

它仅仅提供了一些基础的功能和 API。但是,基于这些基础功能和API,产生了许多强大框架

如:

基于  Express 框架( http://www.expressjs.com.cn/),可以快速构建一个 Web应用
基于  Electron 框架( https://electronjs.org/),可以构建跨平台的桌面应用
基于  restify 框架( http://restify.com/),可以快速构建 API 接口项目

只要你会JavaScript,你就可以用node.js写后端,Springboot+SpringMVC+Mybatis能做的,你都可以使用node.js来实现!

模块化

普遍概念:

模块化是指解决一个复杂问题时,自顶向下逐层把系统 划分成若干模块的过程。对于整个系统来说,模块是 可组合、分解和更换的单元

编程领域的模块化:

编程领域中的模块化,就是遵守固定的规则,把 一个大文件拆成独立并互相依赖的多个小模块

作用:

提高了代码的 复用性
提高了代码的 可维护性
可以实现 按需加载

那么Node.js中是怎样实现模块化的呢?

⚫  内置模块(由 Node.js 官方提供,例如 fs、path、http 等)
⚫  自定义模块(用户创建的每个 .js 文件)
 第三方模块(由第三方开发出来的模块,使用前需要先下载),又叫做 包(重要)
, 即第三方模块是基于内置模块封装出来的,提供了更高级、更方便的 API, 极大的提高了开发效率

而这些模块通常使用 node.js中的 require() 方法加载进行使用

const fs = require('fs') //加载内置的 fs 模块,用于读写文件 

const router = require(./userRouter.js) //加载用户自定义的js文件 

const express = require('express') //加载第三方模块express,用于创建和配置服务器实例
每个模块文件都通过 module.exportsexports来将模块内的成员共享出去,供外界使用。
外界用 require() 方法导入自定义模块时,得到的就是  module.exports 所指向的对象

这里注意区分module.exports和exports, exports是为了简化前者的编写而生的

默认情况下,exports 和 module.exports 指向同一个对象。但最终共享的结果,还是以 module.exports 指向的对象为准

图源:黑马程序员

这里让我们看看CommonJS的规定:

CommonJS 规定了模块的特性和各模块之间 如何相互依赖
① 每个模块内部,module 变量代表当前模块。
② module 变量是一个对象,它的 exports 属性(即 module.exports)是对外的接口。
③ 加载某个模块,其实是加载该模块的 module.exports 属性。require() 方法用于加载模块

npm(Node Package Manager)

概念:

NPM是随同NodeJS一起安装的 包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:
1.允许用户从NPM服务器 下载别人编写的第三方包到本地使用。
2.允许用户从NPM服务器 下载并安装别人编写的命令行程序到本地使用。
3.允许用户将自己 编写的包或命令行程序上传到NPM服务器供别人使用。

npm 规定,在项目根目录中,必须提供一个叫做 package.json 的包管理配置文件。用来记录与项目有关的一些配置

信息。例如:

⚫ 项目的 名称、版本号、描述
⚫ 项目中都用到了 哪些包
⚫ 哪些包只在开发期间会用到
⚫ 那些包在开发和部署时都需要用到

如何快速创建 package.json?

//对于项目起始的空文件夹 
npm init -y 
//运行 npm install 命令安装包的时候, npm会自动把包的名称和版本号,记录到 package.json 中

注意:上述命令只能在英文的目录下成功运行!所以项目的根目录名字,不能有英文,也不能有空格

该文件中的dependencies结点,记录着项目安装的所有包和版本号

拿到别人的项目时,如果项目文件夹中没有项目需要的包(因为包存储文件夹node_modules文件夹过大,通常项目编写者不会把它上传到github等网站),你可以使用

npm i

安装package.json的dependencies结点下的所有包

快速搭建配置一个NodeJs的新项目

可以参考我的项目文件夹结构

1. 创建项目

1.1 新建 server 文件夹,作为项目根目录,并在根目录中运行如下的命令,初始化包管理配置文件:

npm init -y

然后你的项目中就会出现pakage.json文件了

1.2 安装特定版本的 express:

npm i express@4.17.1 

web服务器的一个流行框架,用来创建和配置服务器实例

1.3 在项目根目录中新建 app.js 作为整个项目的入口文件,并初始化如下的代码:

// 导入 express 模块 
const express = require('express') 
// 创建 express 的服务器实例 
const app = express() ​ 

// 之后的其他配置都写在这里 ​ 

// 调用 app.listen 方法,指定端口号并启动web服务器 
app.listen(8888, function () {   
console.log('server is running at http://127.0.0.1:8888') 
})

并在package.json中修改项目的入口为app.js

然后就能在cmd上输入 node ./app.js 启动服务器啦

2. 配置 cors 跨域

2.1 安装 cors 中间件:

npm i cors@2.8.5

2.2 在 app.js 中导入并配置 cors 中间件:

// 导入 cors 中间件 
const cors = require('cors') 

// 将 cors 注册为全局中间件,允许跨域请求 
app.use(cors())

3. 配置解析表单数据的中间件和路由

3.1 配置解析 application/x-www-form-urlencoded 格式的表单数据的中间件,不然服务器无法解析post请求中的请求体body里为表单数据格式的参数

app.use(express.urlencoded({ extended: false }))

3.2 初始化路由相关的文件夹

  1. 在项目根目录中,新建 router 文件夹,用来存放所有的路由模块 路由模块中,只存放客户端的请求与处理函数之间的映射关系
  2. 在项目根目录中,新建 router_handler 文件夹,用来存放所有的 路由处理函数模块 路由处理函数模块中,专门负责存放每个路由对应的处理函数

类似SSM框架中的service接口和serviceImpl类的关系

3.3 初始化用户路由模块

在 router 文件夹中,新建 user.js 文件(举个例子),作为用户的路由模块,并初始化代码格式如下:

const express = require('express') 
const router = express.Router() 

// 导入用户路由处理函数模块 
const userHandler = require('../router_handler/user') 
// 处理登录请求的映射关系 
router.post('/login', userHandler.login) 
 
module.exports = router

在 /router_handler/user.js 中,使用 exports 对象,分别向外共享对应的 路由处理函数 :

/**
 * 在这里定义和用户相关的路由处理函数,供 /router/user.js 模块进行调用
 */
​
// 登录请求的处理函数
exports.login = (req, res) => {
  res.send('login OK')
}

在 app.js 中,导入并使用 用户路由模块 :

// 导入并注册用户路由模块
const userRouter = require('./router/user')

app.use('/api', userRouter)

4. 安装并配置 mysql 这个第三方模块,来连接和操作 MySQL 数据库

4.1 安装 mysql 模块:

npm i mysql@2.18.1

4.2 在项目根目录中新建 /db/index.js 文件,在此自定义模块中创建数据库的连接对象:

// 导入 mysql 模块
const mysql = require('mysql')
​
// 创建数据库连接对象
const db = mysql.createPool({
  host: '127.0.0.1',
  user: 'root',
  password: 'root',
  database: 'db_name',
})
​
// 向外共享 db 数据库连接对象
module.exports = db

5. 配置bcryptjs

在当前项目中,使用 bcryptjs 对用户密码进行加密,

优点:

加密之后的密码, 无法被逆向破解
同一明文密码多次加密,得到的 加密结果各不相同,保证了安全性

5.1 运行如下命令,安装指定版本的 bcryptjs :

npm i bcryptjs@2.4.3

5.2 在 /router_handler/user.js 中,导入 bcryptjs :

const bcrypt = require('bcryptjs')

5.3 若有注册功能,可以在注册用户的处理函数中,确认用户名可用之后,调用 bcrypt.hashSync(明文密码, 随机盐的长度) 方法,对用户的密码进行加密处理:

加密:
// 对用户的密码,进行 bcrype 加密,返回值是加密之后的密码字符串
userinfo.password = bcrypt.hashSync(userinfo.password, 10)
解密:
// 拿着用户输入的密码,和数据库中存储的密码进行对比
const compareResult = bcrypt.compareSync(用户输入的密码, 数据库中加密的密码)
表单验证的原则:前端验证为辅,后端验证为主,后端 永远不要相信前端提交过来的 任何内容

6. 配置表单验证模块

使用 if...else... 的形式对数据合法性进行验证,效率低、出错率高、又不方便维护。因此,可以选择使用第三方数据验证模块,来降低出错率、提高验证的效率与可维护性,让我们可以把更多的精力放在核心业务逻辑的处理上

6.1 安装 joi 包,为表单中携带的每个数据项,定义验证规则:

npm install joi

6.2 安装 @escook/express-joi 中间件,来实现自动对表单数据进行验证的功能:

npm i @escook/express-joi

6.3 新建 /schema/user.js 用户信息验证规则模块,并初始化代码如下:

const joi = require('joi')
​
/**
 * string() 值必须是字符串
 * alphanum() 值只能是包含 a-zA-Z0-9 的字符串
 * min(length) 最小长度
 * max(length) 最大长度
 * required() 值是必填项,不能为 undefined
 * pattern(正则表达式) 值必须符合正则表达式的规则
 */
​
// 用户名的验证规则
const username = joi
  .string()
  .alphanum()
  .min(1)
  .max(10)
  .required()
// 密码的验证规则
const password = joi
  .string()
  .pattern(/^[\S]{6,12}$/)
  .required()
​
// 向外共享登录表单的验证规则对象
exports.reg_login_schema = {
  // 表示需要对 req.body 中的数据进行验证
  body: {
    username,
    password,
  },
}

6.4 修改 /router/user.js 中的代码如下:

const express = require('express')
const router = express.Router()
​
// 导入用户路由处理函数模块
const userHandler = require('../router_handler/user')
​
// 1. 导入验证表单数据的中间件
const expressJoi = require('@escook/express-joi')
// 2. 导入需要的验证规则对象
const { reg_login_schema } = require('../schema/user')
​
// 登录
// 3. 在用户登录的路由中,声明局部中间件,对当前请求中携带的数据进行验证
// 3.1 数据验证通过后,会把这次请求流转给后面的路由处理函数
// 3.2 数据验证失败后,终止后续代码的执行,并抛出一个全局的 Error 错误
router.post('/login', reg_login_schema, userHandler.login)
​
module.exports = router

7. 生成 JWT 的 Token 字符串

在生成 Token 字符串的时候,一定要剔除  密码 和  头像 等隐私的值,以保证用户信息安全

7.1 通过 ES6 的高级语法,快速剔除 密码 的值:

// 剔除完毕之后,user 中只保留了用户的 id, username, nickname, email 这四个属性的值
const user = { ...results[0], password: '' }

7.2 安装生成 Token 字符串的包:

npm i jsonwebtoken@8.5.1

7.3 在 /router_handler/user.js 模块的头部区域,导入 jsonwebtoken 包:

// 用这个包来生成 Token 字符串 
const jwt = require('jsonwebtoken')

7.4 创建 config.js 文件,并向外共享 加密 和 还原 Token 的 jwtSecretKey 字符串:

module.exports = {   jwtSecretKey: 'CodeGoat24 ^_^', }

7.5 将用户信息对象加密成 Token 字符串:

// 导入配置文件
const config = require('../config')
​
// 生成 Token 字符串
const tokenStr = jwt.sign(user, config.jwtSecretKey, {
  expiresIn: '10h', // token 有效期为 10 个小时
})

7.6 将生成的 Token 字符串响应给客户端:

res.send({
  status: 0,
  message: '登录成功!',
  // 为了方便客户端使用 Token,在服务器端直接拼接上 Bearer 的前缀
  token: 'Bearer ' + tokenStr,
})

8 配置解析 Token 的中间件

8.1 运行如下的命令,安装解析 Token 的中间件:

npm i express-jwt@5.3.3

8.2 在 app.js 中注册路由之前,配置解析 Token 的中间件:

// 导入配置文件
const config = require('./config')
​
// 解析 token 的中间件
const expressJWT = require('express-jwt')
​
// 使用 .unless({ path: [/^\/api\//] }) 指定哪些接口不需要进行 Token 的身份认证
app.use(expressJWT({ secret: config.jwtSecretKey }).unless({ path: [/^\/login\//] }))

总结:

看到这里,你是否对NodeJs有了进一步的了解了呢?NodeJs项目虽然在项目搭建阶段会涉及到比较多的配置,但是搭建好之后,在业务逻辑方面的编写就非常方便了,而搭建NodeJs新项目对一些常用包进行基本配置,跟着我上面的步骤就足够啦!,这边推荐像我上面将路由处理的功能模块分为router文件夹和router_handler文件夹,模仿SSM框架在业务层和持久层的文件夹结构。router 文件夹只存放客户端的请求与处理函数之间的映射关系,router_handler 文件夹专门负责存放每个路由对应的处理函数,这样路由功能的目录结构会更加清晰!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680047.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Linux文件系统的缓冲区问题

目录 一.什么是缓冲区? 1.1实验案例1: 情况1:运行该程序 情况2:此时我将该程序运行的结果输出重定向到一个文本文件中: 二.为什么要有缓冲区? 于是引出了缓冲区的刷新策略: 三.缓冲区在哪…

【学习笔记】 科目一之计算题篇

【学习笔记】 科目一之计算题篇 三点估算PERT 三点估算期望:(悲观+4*最可能+乐观)/6三点估算标准差:(悲观-乐观)/6正态分布四个数:34.1%,13.65%,2.1%,0.15%决策树 分叉计算注意:成本越小越好投资回报:收益-投入投资回报率(ROI)=收益-投入/投入投资回收期 静态回…

算法--PageRank

概念 PageRank是Google提出的算法,用于衡量特定网页相对于搜索引擎索引中的其他网页而言的重要程度。是Google创始人拉里佩奇和谢尔盖布林于1997年创造的PageRank实现了将链接价值概念作为排名因素。 GOOGLE PageRank并不是唯一的链接相关的排名算法,而…

如何提升 MySQL 的查询速度?

💂 个人网站:【海拥】【游戏大全】【神级源码资源网】🤟 前端学习课程:👉【28个案例趣学前端】【400个JS面试题】💅 寻找学习交流、摸鱼划水的小伙伴,请点击【摸鱼学习交流群】 目录 前言优化数据库结构1 使…

QT(一) 安装 QT(二)

第一章 : Qt 安装 下载地址安装 打开 cmd 运行镜像 : qt-unified-windows-x64-4.6.0-online.exe --mirror https://mirrors.aliyun.com/qt Hello 因为是qmake 所以是.proCtrl R 直接运行 第二章 GUI程序设计基础 main文件 *.ui : 有UI设计器自动生成…

【工具】Spring 历史官方文档理解(持续更新)

文章目录 [1] Spring Framework 5.2.24CoreAOP 概念AspectJoin pointAdvicePointcutIntroductionTarget objectAOP proxyWeaving Spring AOPAspectJ官方 demo 学习 Pointcut 表达式官方 demo 学习 Advice 声明官方 demo 学习 Introductions (接口拓展)AO…

0004Java程序设计-SSM+JSP医院挂号系统

摘 要 医院挂号,一直以来就是困扰医院提高服务水平的重要环节,特别是医疗水平高、门诊访问量高的综合型医院,门诊拥挤就成了普遍现象。因此,本文提出了医院挂号系统。预约挂号,是借助信息化的技术,面向全社…

代码随想录二刷 day32 | 贪心之 122.买卖股票的最佳时机II 55. 跳跃游戏 45.跳跃游戏II

这里写目录标题 122.买卖股票的最佳时机II55. 跳跃游戏45.跳跃游戏II 122.买卖股票的最佳时机II 题目链接 解题思路: 首先要清楚两点: 只有一只股票!当前只有买股票或者卖股票的操作 想获得利润至少要两天为一个交易单元。 代码如下&#x…

【Unity每日一记】时间Time类-做时间管理大师

👨‍💻个人主页:元宇宙-秩沅 👨‍💻 hallo 欢迎 点赞👍 收藏⭐ 留言📝 加关注✅! 👨‍💻 本文由 秩沅 原创 👨‍💻 收录于专栏:uni…

独立开发变现周刊(第92期):创建一个年收入350万美元的小工具,1000万至1500万美元出售...

分享独立开发、产品变现相关内容,每周五发布。 目录 1、Vercel AI: 使用React, Svelte和Vue快速构建 AI 驱动的应用2、Novel:AI自动补全功能的Notion风格所见即所得编辑器3、Notionbase: 通过Notion轻松建立你的AI聊天机器人4、Plasmo: 一款功能强大的浏…

Python入门教程+项目实战-14.1节-程序实战-二分查找算法

目录 14.1.1 理解函数类型 14.1.2 函数的定义 14.1.3 函数的形参,实参,以及调用 14.1.4 函数的返回值 14.1.5 函数的命名规范 14.1.6 知识要点 14.1.7 系统学习python 14.1.1 理解函数类型 在Python中,函数也是一种数据类型。在理解函…

C++——详解类模板与友元函数

纵有疾风起,人生不言弃。本文篇幅较长,如有错误请不吝赐教,感谢支持。 💬文章目录 类模板与友元函数1️⃣非模板友元函数2️⃣约束模板友元函数3️⃣非约束模板友元函数 类模板与友元函数 模板类的友元函数有三类: …

Qt/C++编写手机版本视频播放器和Onvif工具(可云台和录像)

一、前言 用Qtffmpeg写播放器很多人有疑问,为何不用Qt自己的多媒体框架来写,最重要的原因是Qt自带的目前都依赖具体的本地解码器,如果解码器不支持,那就是歇菜的,最多支持个MP4格式,而且在手机上也都是支持…

C国演义 [第七章]

第七章 最长重复子数组题目理解步骤dp含义递推公式初始化为啥dp数组如此奇怪 遍历顺序 代码 最长公共子序列题目理解步骤dp含义递推公式初始化遍历顺序 代码 总结 最长重复子数组 力扣链接 给两个整数数组 nums1 和 nums2 ,返回 两个数组中 公共的 、长度最长的子…

设计模式之中介者模式笔记

设计模式之中介者模式笔记 说明Mediator(中介者)目录中介者模式示例类图抽象中介者类抽象同事类租房者类房主类具体的中介者角色类测试类 说明 记录下学习设计模式-中介者模式的写法。JDK使用版本为1.8版本。 Mediator(中介者) 意图:用一个中介对象来封装一系列的对象交互。…

剑指 Offer 68 - II. 二叉树的最近公共祖先 / LeetCode 236. 二叉树的最近公共祖先(搜索与回溯)

题目: 链接:剑指 Offer 68 - II. 二叉树的最近公共祖先;LeetCode 236. 二叉树的最近公共祖先 难度:中等 上一题博客:剑指 Offer 68 - I. 二叉搜索树的最近公共祖先 / LeetCode 235. 二叉搜索树的最近公共祖先&#xf…

python:并发编程(二十四)

前言 本文将和大家一起探讨python并发编程的实际项目:win图形界面应用(篇六,共八篇),系列文章将会从零开始构建项目,并逐渐完善项目,最终将项目打造成适用于高并发场景的应用。 本文为python并…

Pandas进阶修炼120题-第二期(Pandas数据处理,21-50题)

文章目录 Pandas进阶修炼120题第二期 Pandas数据处理21.读取本地EXCEL数据22.查看df数据前5行23.将salary列数据转换为最大值与最小值的平均值方法一:正则表达式(分别使用apply(),applymap(),map()来实现)方法二:apply…

wifi芯片原理

一、在系统中的位置 基带(baseband) 基带的作用有三个: 1、队列包的管理 2、调试解调 3、CSMA/CA机制 CSMA/CA的全称是Carrier Sense Multiple Access with Collision Avoidance,即载波侦听多路访问/冲突避免。 各…

java——集合框架

文章目录 接口实现(类)算法1. 排序算法2. 查找算法3. 拷贝算法4. 填充算法5. 比较算法6. 随机算法7. 迭代器算法8. 交集、并集、差集9. 分割集合10. 数组和集合的互转 集合框架是一个用来代表和操纵集合的统一架构。所有的集合框架都包含如下内容&#x…