总结Node.js模块开发及常用技巧分享

一、模块化

模块化做为一种现代化的设计方法,这个概念最早起源于生产制造行业。如今这个概念已经被各行各业来衍生应用,在软件开发中也大量的采用了模块化思想。

所谓的模块化思想,将一个大程序按照功能划分为若干个小的模块,每个小程序模块完成一个特定的功能,所有的模块按某种方法组装起来,成为一个整体,完成整个系统所要求功能的程序设计方法。【推荐:node.js视频教程】

(一)、为什么需要模块化

模块化可以使你的代码低耦合,功能模块直接不相互影响。

为什么需要模块化:

程序复杂度上升代码越写越多,在一个文件里代码就会越来越长,不易维护。(把完成特定功能的代码分组,分别放到不同的文件里,这样,每个文件包含的代码就相对较少)

JavaScript 有复杂的依赖关系的时候就很容易出现一些变量的属性或方法被覆盖或改写,导致变量污染。这是因为js没有命名空间,不像其他语言通过命名空间可以有效的避免重名问题。

想要存在JavaScript 私有的变量

模块化思想解决问题:

可维护性:每个模块都是单独定义的,之间相互独立。模块尽可能的需要和外部撇清关系,方便我们独立的对其进行维护与改造。维护一个模块比在全局中修改逻辑判断要好的多。

命名冲突:为了避免在JavaScript中的全局污染,我们通过模块化的方式利用函数作用域来构建命名空间,避免命名冲突。

文件依赖:一个功能可能依赖一个或多个其他文件,使用是除了引入它本身还需要考虑依赖文件,通过模块化 我们只需要引入文件,无需考虑文件依赖(模块化可以帮助我们解决文件依赖问题)。

可复用性:虽然粘贴复制很简单,但是要考虑到我们之后的维护以及迭代。

(二)、什么是Nodejs模块

为了让Nodejs的文件可以相互调用,Nodejs基于CommonJS规范提供了一个简单的模块系统。(nodejs实现并遵守CommonJS规范的)。

把具有公共功能的,抽离成一个单独的js文件作位一个模块。默认情况下,模块里的方法或属性,外面是访问不到的。如果想要在外面访问这些属性,方法,就必须在模块里通过exportsmodule.exports暴露,在需要使用的地方通过require()进行引入。

//exports语法示例// sum.jsexports.sum = function(a,b){    return a+b;}// main.jsvar m = require("./sum");var num = m.sum(10,20);console.log(num);//modules.exports语法示例//sum.jsfunction sum(a,b){    return a+b;}module.exports= sum;//main.jsvar sum = require('./sum');sum(10,20);// 30

CommonJS 规定:

每个模块内部,module 变量代表当前模块

module 变量是一个对象,它的 exports 属性(即 module.exports)是对外的接口

加载某个模块,其实是加载该模块的 module.exports 属性。require() 方法用于加载模块。

(三)、nodejs中的模块分类与加载方式

Node.js 中根据模块来源的不同,将模块分为了 3 大类,分别是:

内置模块(内置模块是由 Node.js 官方提供的,例如 fs、path、http 等)

自定义模块(用户创建的每个 .js 文件,都是自定义模块)

第三方模块(包)(由第三方开发出来的模块,并非官方提供的内置模块,也不是用户创建的自定义模块,使用前需要先下载)

//1.加载内置模块不需要指定路径var http = require('http');//2.加载用户的自定义模块var sum = require('./sum.js');//3.加载第三方模块const md5=require("md5");

(四)、模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问,这种模块级别的访问限制,叫做模块作用域。模块作用域的好处:防止了全局变量污染的问题

二、npm与包

(一)、包的介绍

Node.js 中的第三方模块又叫做包。包是由第三方个人或团队开发出来的,免费供所有人使用。Node.js 的内置模块仅提供了一些底层的 API,导致在基于内置模块进行项目开发的时,效率很低。
包是基于内置模块封装出来的,提供了更高级、更方便的 API,极大的提高了开发效率。国外有一家 IT 公司,叫做 npm, Inc. 这家公司旗下有一个非常著名的网站: https://www.npmjs.com/ ,它是全球最大的包共享平台。我们可以使用这个包管理工具, npm ,来对包进行管理,这个包管理工具随着 Node.js 的安装包一起被安装到了用户的电脑上。检测其版本。npm -v

(二)、npm的使用

npm init 进行初始化,生成package.json 文件,记录项目的信息,记录包的信息npm install 包名 npm i 包名 下载包,放到node_modules文件夹里npm i 包名 --save npm i 包名 -S (开发环境中)npm i 包名 --save-dev npm i 包名 -D (生产环境中)npm list 列举当前目录下安装的包npm i 包名@1 安装指定的版本npm i 包名 -g 安装全局包npm uninstall 包名 卸载包

(三)、全局安装nrm nodemon

nrm 是一个管理 npm 源的工具。有时候国外资源太慢,使用这个就可以快速的在npm源间切换。

手动切换方法:

npm config set registry=https://registry.npm.taobao.org

安装 nrm:

$ npm i nrm -g

查看nrm 内置的几个 npm 源的地址:

$ nrm ls

结果如下:

  npm ---- https://registry.npmjs.org/  cnpm --- http://r.cnpmjs.org/* taobao - https://registry.npm.taobao.org/  nj ----- https://registry.nodejitsu.com/  rednpm - http://registry.mirror.cqupt.edu.cn/  npmMirror  https://skimdb.npmjs.com/registry/  edunpm - http://registry.enpmjs.org/

切换nrm:

$ nrm use npm

查看当前的镜像源:

npm config get register

(四)、淘宝cnpm工具

淘宝 NPM 镜像是一个完整 npmjs.org 镜像,你可以用此代替官方版本(只读),同步频率目前为 10分钟 一次以保证尽量与官方服务同步。

你可以使用淘宝定制的 cnpm (gzip 压缩支持) 命令行工具代替默认的 npm:

npm install -g cnpm -registry=https://registry.npm.taobao.org

安装包

cnpm install [模块名]

三、路由

路由:根据不同的路径返回不同的页面。

案例:server.js;static;route.js;route对象;render();api.js;封装server.js到index.js;合并对象

获取请求参数:login页面发get,post请求,到/api/login

静态资源托管:

express

Express是一个基于 Node.js 平台,快速、开放、极简的 Web 开发框架。

一、下载与安装

$ npm install express --save

案例:第一个express案例。

二、路由

所谓的路由就是客户端用来与后端服务器进行交互的一种方式,客户端采用特定的URL与请求方法来访问服务器端,服务器端通过响应返回特定资源。

路由的定义由如下结构组成:

app.METHOD(PATH, HANDLER)
名称 描述

appapp 是一个 express 实例METHODMETHOD用于指定要匹配的HTTP请求方式PATHPATH是服务器端的路径HANDLER是当路由匹配时需要执行的处理程序(回调函数)

路由路径和请求方法一起定义了请求的端点,它可以是字符串,字符串模式以及正则表达式。

app.get('/', function (req, res) {  res.send('root')})app.get('/about', function (req, res) {  res.send('about')})app.get('/random.text', function (req, res) {  res.send('random.text')})

使用字符串模式的路由路径示例:

app.get('/ab?cd', function (req, res) {  res.send('ab?cd')  //abcd ,acd})app.get('/ab/:id', function (req, res) {  res.send('ab/:id')  })app.get('/ab+cd', function (req, res) {  res.send('ab+cd')    //b可以一次或者多次的重复})app.get('/ab*cd', function (req, res) {  res.send('ab*cd')  //在ab,cd之间随意写入任意字符})app.get('/ab(cd)?e', function (req, res) {  res.send('ab(cd)?e')})

可以为请求处理提供多个回调函数,其行为类似中间件。

案例:中间件f1,f2

app.get('/example/b', function (req, res, next) {  console.log('the response will be sent by the next function ...')  next()}, function (req, res) {  res.send('Hello from B!')})
var cb0 = function (req, res, next) {  console.log('CB0')  next()}var cb1 = function (req, res, next) {  console.log('CB1')  next()}var cb2 = function (req, res) {  res.send('Hello from C!')}app.get('/example/c', [cb0, cb1, cb2])
var cb0 = function (req, res, next) {  console.log('CB0')  next()}var cb1 = function (req, res, next) {  console.log('CB1')  next()}app.get('/example/d', [cb0, cb1], function (req, res, next) {  console.log('the response will be sent by the next function ...')  next()}, function (req, res) {  res.send('Hello from D!')})

三、中间件

1.应用级中间件

在Express程序中,使用 app.use()app.METHOD() 方法将中间件绑定到应用程序对象(app)。

凡是挂载在app身上的都是应用级中间件。

app.use() : 应用中的每个请求都可以执行其代码

//万能中间件var express = require('express')var app = express()app.use(function (req, res, next) {    console.log('Time:', Date.now())    next()})
//特定路由的应用中间件app.use("/login",function (req, res, next) {    console.log('Time:', Date.now())})

2.路由级中间件

路由器级中间件的工作方式与应用级中间件相同,只是它绑定到express.Router().

var router = express.Router()
var express = require('express')var app = express()var router = express.Router()router.use(function (req, res, next) {    console.log('Time:', Date.now())    next()})router.get('/user/:id', function (req, res, next) {    console.log('Request URL:', req.originalUrl)    next()}, function (req, res, next) {    console.log('Request Type:', req.method)    next()})

案例: / ; /home , /list

3.错误处理中间件

与其他中间件函数相同的方式定义错误处理中间件函数,但是使用四个参数(err, req, res, next),放到最后。

app.use(function (err, req, res, next) {  console.error(err.stack)  res.status(404).send('Something broke!')})

4.内置中间件

express.static提供静态资源,例如 HTML 文件、图像等。

express.json使用 JSON 有效负载解析传入请求。注意:可用于 Express 4.16.0+

application/json

由于JSON规范的流行,现在越来越多的开发者将application/json这个Content-Type作为响应头。用来告诉服务端消息主体是序列化后的JSON字符串。除了低版本IE之外各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理JSON的函数,JSON能格式支持比键值对复杂得多的结构化数据,普通键值对中的值只能是字符串,而使用json,键值对可以重复嵌套。

// 应用级别中间件,获取post--json参数app.use(express.json());

express.urlencoded解析带有 URL 编码负载的传入请求。 注意:可用于 Express 4.16.0+

application/x-www-form-urlencoded
浏览器的原生form表单,如果不设置enctype属性,那么最终就会以 application/x-www-form-urlencoded方式提交数据。Content-Type被指定为application/x-www-form-urlencoded提交的数据按照key=val&key=val的方式进行编码,并且key和val都进行了URL转码。

// 应用级别中间件,获取post--form参数app.use(express.urlencoded({extended:false}));

5.第三方中间件

四、获取请求参数

req.query 是一个可获取客户端get请求 查询字符串 转成的对象,默认为{}。req.body 包含在请求体中提交的数据键值对。默认情况下undefined,当使用解析中间件express.json()express.urlencoded()

五、静态资源托管

为了提供诸如图像、CSS 文件和 JavaScript 文件之类的静态文件,请使用 Express 中的 express.static 内置中间件函数。

语法:

express.static内置中间件函数语法:

express.static(root, [options])

root参数指定提供静态资源的根目录。

静态资源示例:

例如,通过如下代码就可以将 public 目录下的图片、CSS 文件、JavaScript 文件对外开放访问了:

app.use(express.static('public'))

现在,你就可以访问 public 目录中的所有文件了:

http://localhost:3000/images/kitten.jpghttp://localhost:3000/css/style.csshttp://localhost:3000/js/app.jshttp://localhost:3000/images/bg.pnghttp://localhost:3000/hello.html

Express 在静态目录查找文件,因此,存放静态文件的目录名不会出现在 URL 中。

多个静态资源目录:

如果要使用多个静态资源目录,请多次调用 express.static 中间件函数:

app.use(express.static('public'))app.use(express.static('uploads'))

访问静态资源文件时,express.static 中间件函数会根据目录的添加顺序查找所需的文件。

虚拟路径:(非得添加static,没有意义)

express.static中间件函数可以为某些静态资源服务创建虚拟路径前缀(该路径实际上并不存在于文件系统中),请指定静态目录的挂载路径,如下所示:

app.use('/static', express.static('public'))

现在,你就可以通过带有 /static 前缀地址来访问 public 目录中的文件了。

http://localhost:3000/static/images/kitten.jpghttp://localhost:3000/static/css/style.csshttp://localhost:3000/static/js/app.jshttp://localhost:3000/static/images/bg.pnghttp://localhost:3000/static/hello.html

六、模板引擎

一、.服务端渲染 SSR

后端嵌套模板,后端渲染模板 (后端把页面组装起来)

做好静态页面,动态效果把前端代码提供给后端,后端要把静态html以及里面的假数据给删掉,通过模板进行动态生成html的内容

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jL70ca3p-1658387147221)(C:Users11933Desktop前端全栈课件前后台交互imgs服务器端渲染.png)]

二、前后端分离,BSR

(前后端分离,通过通用的json数据形式,不挑后端的语言)

做好静态页面,动态效果json模拟,ajax动态创建页面真实接口数据,前后联调

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pXRCidw2-1658387147223)(C:Users933Desktop前端全栈课件前后台交互imgs前后端分离.png)]

JTBC网站内容管理系统 JTBC网站内容管理系统

JTBC网站内容管理系统是一套可对现有模块进行扩充与克隆的网站系统核心,采用UTF-8编码,采取 语言-代码-程序两两分离的技术模式,全面使用了模板包与语言包结构,为用户的修改提供方便,网站内容的每一个角落都可以在后台予以管理,是一套非常适合用做系统建站或者进行二次开发的程序核心

JTBC网站内容管理系统 71 查看详情 JTBC网站内容管理系统

三、模板引擎

模板引擎能够在应用程序中使用静态模板文件。在运行时,模板引擎将模板文件中的变量替换为实际值,并将模板转换为发送给客户端的 HTML 文件。这种方法使设计 HTML 页面变得更加容易。

Express模板引擎

与 Express 一起使用的一些流行模板引擎是Pug、 Mustache和EJS。Express 应用程序生成器默认使用Pug,但它也支持其他几个。

需要在应用中进行如下设置才能让Express渲染模板引擎:

views,放模板文件的目录。例如:app.set('views', './views')。view engine,要使用的模板引擎。例如,要使用 Pug 模板引擎:app.set('view engine', 'pug').

在路由中渲染模板

在路由渲染模板并将渲染后的 HTML 字符串发送到客户端。

res.render(view [, locals] [, callback])

view:一个字符串,view是要渲染的模板文件的文件路径。locals:一个对象,其属性定义视图的局部变量。

app.get('/', function (req, res) {  res.render('index', { title: 'Hey', message: 'Hello there!' })})
四、ejs模板引擎的使用
安装ejs
npm install ejs
在express配置ejs模板引擎
使用ejs模板引擎

在app.js中添加如下代码,配置Express使用ejs模板引擎。

app.set('views',path.join(__dirname,'views')); //设置模板存储位置app.set('view engine','ejs');

注意:此时指定的模板目录为views,且模板文件的后缀名为.ejs

设置模板后缀为html

在app.js中添加如下代码,配置Express使用ejs模板引擎。并指定模板后缀名为html。

app.set('views',path.join(__dirname,'views')); //设置模板存储位置app.set('view engine','html');app.engine('html',require('ejs').renderFile); //使用ejs模板引擎解析html

注意:此时指定的模板目录为views,且模板文件的后缀名为.html

ejs模板语法
   输出标签   输出html标签(html会被浏览器解析)   注释标签    流程控制标签(写的是if,else,for)  导入公共的模板内容

MVC框架:

是一种设计模式,是软件架构得模式,是在web开发过程中总结的一些套路或者是模块化的内容。M是指业务模型(module),V是指用户界面(view),C则是控制器(controller)。使用mvc最大的优势就是分层,目的是将M和V的实现代码分离,存在的目的则是确保M和V的同步,一旦M改变,V应该同步更新。MVC是相互独立的,M,C(后端); V(前端)。路由规划为Controller。

JSON:

一、概念:

JSON(JavaScript Object Notation, JS对象表示法)简单来讲,JSON 就是 Javascript 对象和数组的字符串表示法,因此,JSON 的本质是字符串。

作用:JSON 是一种轻量级的文本数据交换格式,在作用上类似于 XML,专门用于存储和传输数据,但是 JSON 比 XML 更小、更快、更易解析。

现状:JSON 是在 2001 年开始被推广和使用的数据格式,到现今为止,JSON 已经成为了主流的数据交换格式。

二、JSON的两种结构

JSON 就是用字符串来表示 Javascript 的对象和数组。所以,JSON 中包含对象和数组两种结构,通过这两种结构的相互嵌套,可以表示各种复杂的数据结构。

对象结构:对象结构在 JSON 中表示为 { } 括起来的内容。数据结构为 { key: value, key: value, … } 的键值对结构。其中,key 必须是使用英文的双引号包裹的字符串,value 的数据类型可以是数字、字符串、布尔值、null、数组、对象6种类型。

{    "name": "zs",    "age": 20,    "gender": "男",    "hobby": ["吃饭", "睡觉"]}

数组结构:数组结构在 JSON 中表示为 [ ] 括起来的内容。数据结构为 [ “java”, “javascript”, 30, true … ] 。数组中数据的类型可以是数字、字符串、布尔值、null、数组、对象6种类型。

[ 100, 200, 300 ][ true, false, null ][ { "name": "zs", "age": 20}, { "name": "ls", "age": 30} ][ [ "aaa", "bbb", "ccc" ], [ 1, 2, 3 ] ]

三、JSON语法的注意事项

属性名必须使用双引号包裹字符串类型的值必须使用双引号包裹JSON 中不允许使用单引号表示字符串JSON 中不能写注释JSON 的最外层必须是对象或数组格式不能使用 undefined 或函数作为 JSON 的值JSON 的作用:在计算机与网络之间存储和传输数据JSON 的本质:用字符串来表示 Javascript 对象数据或数组数据

四、JSON和JS对象的关系

JSON 是 JS 对象的字符串表示法,它使用文本表示一个 JS 对象的信息,本质是一个字符串。

//这是一个对象var obj = {a: 'Hello', b: 'World'}//这是一个 JSON 字符串,本质是一个字符串var json = '{"a": "Hello", "b": "World"}'

五、JSON和JS对象的互转

要实现从 JSON 字符串转换为 JS 对象,使用 JSON.parse() 方法要实现从 JS 对象转换为 JSON 字符串,使用 JSON.stringify() 方法

HTTP

一、概念

HTTP 协议即超文本传送协议 (HyperText Transfer Protocol) ,它规定了客户端与服务器之间进行网页内容传输时,所必须遵守的传输格式。(是一种约定与规则)

二、请求(请求报文)

客户端发起的请求叫做 HTTP 请求,客户端发送到服务器的消息,叫做 HTTP 请求消息,又叫做 HTTP 请求报文。

请求消息的组成

HTTP 请求消息由请求行(request line)、请求头部( header ) 、空行 和 请求体 4 个部分组成。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-G502I2rT-1658387147224)(C:Users11933Desktop前端全栈课件前后台交互imgs请求消息组成部分.png)]

请求行:由请求方式(get,post)、URL (/login?)和 HTTP 协议版本 3 个部分组成,他们之间使用空格隔开。请求头部:用来描述客户端的基本信息,从而把客户端相关的信息告知服务器。请求头部由多行 键/值对 组成,每行的键和值之间用英文的冒号分隔。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ImfA8U4y-1658387147225)(C:Users11933Desktop前端全栈课件前后台交互imgs请求头部字段.png)]

空行:最后一个请求头字段的后面是一个空行,通知服务器请求头部至此结束。请求消息中的空行,用来分隔请求头部与请求体。请求体:请求体中存放的,是要通过 POST 方式提交到服务器的数据。只有 POST 请求才有请求体,GET 请求没有请求体!

三、响应(响应报文)

响应消息就是服务器响应给客户端的消息内容,也叫作响应报文。

响应消息的组成:

HTTP响应消息由状态行、响应头部、空行 和 响应体 4 个部分组成。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-N0rfsHa8-1658387147225)(C:Users11933Desktop前端全栈课件前后台交互imgs响应消息组成部分.png)]

状态行:由 HTTP 协议版本、状态码和状态码的描述文本 3 个部分组成,他们之间使用空格隔开;响应头部:用来描述服务器的基本信息。响应头部由多行 键/值对 组成,每行的键和值之间用英文的冒号分隔。空行:在最后一个响应头部字段结束之后,会紧跟一个空行,用来通知客户端响应头部至此结束。响应消息中的空行,用来分隔响应头部与响应体。响应体:中存放的,是服务器响应给客户端的资源内容。

四、HTTP请求方法

HTTP 请求方法,属于 HTTP 协议中的一部分,请求方法的作用是:用来表明要对服务器上的资源执行的操作。最常用的请求方法是 GET 和 POST。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vwQMQrAp-1658387147226)(C:Users11933Desktop前端全栈课件前后台交互imgshttp请求的方法.png)]

五、响应的状态码

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-28YRkP8m-1658387147227)(C:Users11933Desktop前端全栈课件前后台交互imgshttp响应状态码.png)]

Ajax:

一、概念

AJAX 全称为(Asynchronous JavaScript And XML),是异步的JavaScript和XML。通过 ajax可以在浏览器向服务器发送异步请求。最大的优势,无刷新获取数据 。也就是说AJAX可以在不重新加载整个页面的情况下,与服务器交换数据。这种异步交互的方式,使用户单击后,不必刷新页面也能获取新数据。使用Ajax,用户可以创建接近本地桌面应用的直接、高可用、更丰富、更动态的Web用户界面。

二、XML

XML 指可扩展标记语⾔,HTML 超文本标记语言XML被设计用来传输和存储数据XML和HTML类似,不同的是HTML都是预定义的标签,而XML没有预定义标签,全部都是自定义的标签,用来表示一些数据。

最开始是前后台进行数据交互的语言,现在是JSON。

'{"title":"三体","author":"zs","price":30}'    三体    刘慈欣    30.00

三、特点

优点:

可以无需刷新页面与服务器进行通信允许你根据用户事件来更新部分页面内容

缺点:

没有浏览历史不能回退存在跨越问题 同源策略:协议,域名,端口号SEO不友好

四、发送请求

get方式,以及请求参数

// 1.创建对象var xhr=new XMLHttpRequest();// 2.初始化,设置请求方法和urlxhr.open("GET","http://127.0.0.1:3000/server?username=zs&password=1234");// 3.发送xhr.send();// 4.绑定事件,处理服务端返回得结果// readstate  xhr得属性  状态  0,1,2,3,4xhr.onreadystatechange=function(){    // 服务器返回得结果    if(xhr.readyState==4){        // 判断响应得状态码        if(xhr.status==200){            // 行,头,体            console.log(xhr.status);            console.log(xhr.statusText);            console.log(xhr.response);            console.log(xhr.getAllResponseHeaders());        }    }}

项目:

一、对密码进行加密处理

JavaScript使用CryptoJS加解密。CryptoJS时一个JavaScript的加解密的工具包。它支持多种的算法:MD5、SHA1、SHA2、SHA3、RIPEMD-160 哈希散列,进行 AES、DES、Rabbit、RC4、Triple DES 加解密。在项目中如果要对前后端传输的数据双向加密, 比如避免使用明文传输用户名,密码等数据。 就需要对前后端数据用同种方法进行加密,方便解密。

使用步骤:

运行如下命令,安装 CryptoJS

npm i crypto-js

/login.js 中,导入 crypto-js

const crypto = require('crypto-js')

ASE进行纯文本加密:

//加密var a=crypto.AES.encrypt("abc","key").toString();    //SecrectKey 秘钥//解密var b=crypto.AES.decrypt(a,"key").toString(crypto.enc.Utf8);  //按照UTF8编码解析出原始字符串

二、表单校验规则

在实际开发中,前后端都需要对表单的数据进行合法性的验证,而且,后端做为数据合法性验证的最后一个关口,在拦截非法数据方面,起到了至关重要的作用。使用第三方数据验证模块,来降低出错率、提高验证的效率与可维护性。

步骤:

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

npm install joi

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

npm i @escook/express-joi

新建 /schema/login.js 用户信息验证规则模块:

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

修改 /router/admin/login.js 中的代码:

// 1. 导入验证表单数据的中间件const expressJoi = require('@escook/express-joi')// 2. 导入需要的验证规则对象const { login_schema } = require('../../schema/login');// 3登录功能router.post("/",expressJoi(login_schema),(req,res)=>{}];

index.js 的全局错误级别中间件中,捕获验证失败的错误,并把验证失败的结果响应给客户端:

const joi = require('joi')// 错误中间件app.use(function (err, req, res, next) {  // 数据验证失败  if (err instanceof joi.ValidationError) return res.send(err);  // 未知错误  res.send(err)})

三、四种常见的POST提交数据方式

HTTP协议是以ASCII码传输,建立在TCP/IP协议之上的应用层规范。规范把 HTTP 请求分为三个部分:状态行、请求头、消息主体。协议规定 POST 提交的数据必须放在消息主体(entity-body)中,但协议并没有规定数据必须使用什么编码方式Content-Type。

服务端根据请求头(headers)中的Content-Type字段来获知请求中的消息主体是用何种方式编码,再对主体进行解析。所以说到POST提交数据方案,包含了Content-Type 和消息主体编码方式两部分。Content-Type的四种值分别代表四种方式,具体如下:

方式一:application/x-www-form-urlencoded

浏览器的原生form表单,如果不设置enctype属性,那么最终就会以 application/x-www-form-urlencoded方式提交数据。Content-Type被指定为application/x-www-form-urlencoded提交的数据按照key=val&key=val的方式进行编码,并且key和val都进行了URL转码。服务端例如 PHP 中,使用$_POST[′key′]可以获取到值。

方式二:multipart/form-data

常见的POST数据提交的方式。这种方式支持文件上传,不过必须要设置form的enctyped等于这个值。使用multipart/form-data方式会生成了一个boundary 来分割不同的字段,为了避免与正文重复,boundary是一段很长的随机拼接的字符串。然后Content-Type指明数据是以mutipart/form-data来编码并包括进本次请求的boundary 值。消息主体最后以 –boundary–标示结束。

方式三:application/json

由于JSON规范的流行,现在越来越多的开发者将application/json这个Content-Type作为响应头。用来告诉服务端消息主体是序列化后的JSON字符串。除了低版本IE之外各大浏览器都原生支持 JSON.stringify,服务端语言也都有处理JSON的函数,JSON能格式支持比键值对复杂得多的结构化数据,普通键值对中的值只能是字符串,而使用json,键值对可以重复嵌套。

方式四:text/xml

它是一种使用HTTP作为传输协议,XML作为编码方式的远程调用规范。不过后来使用很少。也许在十多年前,在json还未出来之前数据交互对接。

总之application/x-www-form-urlencoded和multipart/form-data两种POST方式都是浏览器原生支持的,是普遍使用的两种方式,application/json是现在比较流行的新趋势。

四、multer

安装multer

npm i multer

导入multer

const multer  = require('multer')

配置multer接收到的文件存储的文件夹和,存放的图片的名字

//上传文件存放路径、及文件命名const storage = multer.diskStorage({    destination: path.join(__dirname ,'../static/uploads'),  //确定上传文件的物理位置    filename: function (req, file, cb) { //自定义设置文件的名字,根据上传时间的时间戳来命名        let type = file.originalname.split('.')[1]        cb(null, `${file.fieldname}-${Date.now().toString(16)}.${type}`)    }})

1.sotrage是一个配置对象。他是通过multer.diskstorage存储引擎生成的。multer.diskstorage需要传递一个配置对象,这里的配置对象里面接收两个参数。第一个参数为destination,它的值为一个路径字符串,代表的含义是当multer处理完成前端传递过来的文件之后要把这个文件存储在哪里。这个文件夹无需手动创建,在接受文件的时候会自动创建。这里建议使用path模块进行拼接,不容易出错。第二个参数为一个回调函数,这里形参要用三个进行占位。multer中间件在解析前端提交的文件的时候会调用这个方法,调用的时候会给这个filename指向的函数传递三个参数,第二个值为前端传递过来文件信息,第三个参数cb为一个函数,cb函数调用的第二个参数指定的就是当前解析完成后的保存到destination指向的目录的文件名。

应用这个配置到multer实例里面

const upload = multer({storage});

在需要接收文件的路由里面应用upload.single(‘file’)中间件

(1).这个file是前端提交表单过来的时候表单的字段名称。(2).upload是用multer这个库里的顶级构造函数生成的实例。

总体思路梳理:

实际网页开发当中,我们前端需要向后端提交一些像mp4,mp3,图片系列的东西,需要在后端进行接收。那么这里就可以使用Multer中间件来接收文件,对前端传递过来的文件做一些处理。

multer是啥? Multer是Express官方推出的,用于node.js 处理前端以multipart/form-data请求数据处理的一个中间件。注意: Multer 不会处理任何非 multipart/form-data 类型的表单数据

原理: Multer实例的single(‘###’) 是一个方法,这个方法被当作中间件放在某一个路由上时。就会给express 的 request 对象中添加一个 body 对象 以及 file 或 files 对象 。 body 对象包含表单的文本域信息,file 或 files 对象包含对象表单上传的文件信息。下图就是req.file的模样。当前端请求后台接口。匹配当前路由的时候,先经过这个multer中间件,这个中间件就会解析前端传过来的文件,会把文件保存在上面第三步配置文件解析完成后的文件夹内,名字也会重命名成上面第三步配置文件解析完成的文件名。同时,会在req的身上挂载一个file对象。这个file对象就是当前上传文件的信息。我们可以通过req.file.filename拿到这个重命名后的文件名,然后把这个文件名保存到数据库里面。前端如果想访问之前上传的图片,后台只需要把数据库里的文件名取到,随后映射成我们请求的路径,去请求public静态资源下的存放这些文件的文件夹就可以了。

multer是一个中间件,我建议把这个中间件写成一个单独的文件,最后把配置好的multer实例暴露出去,在需要他的路由里面当作中间件去应用它。就可以很快捷的处理前端发送过来的文件。而无需每个文件都写一遍。也更加符合我们模块化编程的思想。下图是我multer文件的配置。

五、富文本编辑器

富文本编辑器,Multi-function Text Editor, 简称 MTE, 是一种可内嵌于浏览器,所见即所得的文本编辑器。它提供类似于 Microsoft Word 的编辑功能,容易被不会编写 HTML 的用户并需要设置各种文本格式的用户所喜爱。

富文本编辑器不同于文本编辑器,程序员可到网上下载免费的富文本编辑器内嵌于自己的网站或程序里(当然付费的功能会更强大些),方便用户编辑文章或信息。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-9D1VzMYl-1658387147228)(C:Users11933Desktop前端全栈课件前后台交互imgs富文本编辑器.png)]

layui 富文本编辑器(layedit):

使用:

layui.use(['layedit'],function(){    layedit.build("demo")})

layedit基础的方法:

方法名 描述

var index = layedit.build(id, options)用于建立编辑器的核心方法index:即该方法返回的索引参数 id: 实例元素(一般为textarea)的id值参数 options:编辑器的可配置项,下文会做进一步介绍layedit.set(options)设置编辑器的全局属性即上述build方法的optionslayedit.getContent(index)获得编辑器的内容参数 index: 即执行layedit.build返回的值layedit.getText(index)获得编辑器的纯文本内容参数 index: 同上layedit.sync(index)用于同步编辑器内容到textarea(一般用于异步提交)参数 index: 同上layedit.getSelection(index)获取编辑器选中的文本参数 index: 同上

编辑器属性设置:

属性 类型 描述

toolArray重新定制编辑器工具栏,如: tool: [‘link’, ‘unlink’, ‘face’]hideToolArray不显示编辑器工具栏,一般用于隐藏默认配置的工具barheightNumber设定编辑器的初始高度uploadImageObject设定图片上传接口,如:uploadImage: {url: ‘/upload/’, type: ‘post’}

富文本编辑器工具栏:

 let richtextInex =  layedit.build('richtext', {     tool: [         'strong' //加粗         , 'italic' //斜体         , 'underline' //下划线         , 'del' //删除线         , '|' //分割线         , 'left' //左对齐         , 'center' //居中对齐         , 'right' //右对齐         , 'image' //插入图片     ],     uploadImage:{url:'/uploadrichtext',type:'POST'} })

六、express-session

(一)、Session简单介绍
session 是另一种记录客户状态的机制,不同的是 Cookie 保存在客户端浏览器中,而 session 保存在服务器上。Session的用途:
session运行在服务器端,当客户端第一次访问服务器时,可以将客户的登录信息保存。
当客户访问其他页面时,可以判断客户的登录状态,做出提示,相当于登录拦截。
session可以和Redis或者数据库等结合做持久化操作,当服务器挂掉时也不会导致某些客户信息(购物车)
丢失。

(二)、Session的工作流程
当浏览器访问服务器并发送第一次请求时,服务器端会创建一个session对象,生成一个类似于
key,value的键值对,然后将key(cookie)返回到浏览器(客户)端,浏览器下次再访问时,携带key(cookie),
找到对应的session(value)。 客户的信息都保存在session中。

(三)、Cookie和Session区别:

cookie 数据存放在客户的浏览器上,session 数据放在服务器上。

cookie 不是很安全,别人可以分析存放在本地的 COOKIE 并进行 COOKIE 欺骗 考虑到安全应当使用 session。

session 会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能 考虑到减轻服务器性能方面,应当使用 COOKIE。

单个 cookie 保存的数据不能超过 4K,很多浏览器都限制一个站点最多保存 20 个 cookie。

(四)、express-session的使用

安装 express-session:

npm install express-session

引入express-session:

var session = require("express-session");

设置官方文档提供的中间件:

app.use(session({    secret: 'keyboard cat',    resave: true,    saveUninitialized: true}))

使用:

设置值 req.session.username = "张三";获取值 req.session.username

express-session的常用参数:

1. name - cookie的名字(原属性名为 key)。(默认:’connect.sid’)2. store - session存储实例3. secret - 用它来对session cookie签名,防止篡改4. cookie - session cookie设置 (默认:{ path: ‘/‘, httpOnly: true,secure: false, maxAge: null })5. genid - 生成新session ID的函数 (默认使用uid2库)6. rolling - 在每次请求时强行设置cookie,这将重置cookie过期时间(默认:false)7. resave - 强制保存session即使它并没有变化 (默认: true)8. proxy - 当设置了secure cookies(通过”x-forwarded-proto” header )时信任反向代理。当设定为true时,”x-forwarded-proto” header 将被使用。当设定为false时,所有headers将被忽略。当该属性没有被设定时,将使用Express的trust proxy。9. saveUninitialized - 强制将未初始化的session存储。当新建了一个session且未设定属性或值时,它就处于未初始化状态。在设定一个cookie前,这对于登陆验证,减轻服务端存储压力,权限控制是有帮助的。(默认:true)10. unset - 控制req.session是否取消(例如通过 delete,或者将它的值设置为null)。这可以使session保持

express-session的常用方法:

1. Session.destroy():删除session,当检测到客户端关闭时调用。2. Session.reload():当session有修改时,刷新session。3. Session.regenerate():将已有session初始化。4. Session.save():保存session。

使用案例:

//配置中间件app.use(session({    secret: 'this is string key',   // 可以随便写。一个 String 类型的字符串,作为服务器端生成 session 的签名    name:'session_id',/*保存在本地cookie的一个名字 默认connect.sid  可以不设置*/    resave: false,   /*强制保存 session 即使它并没有变化,。默认为 true。建议设置成 false。*/    saveUninitialized: true,   //强制将未初始化的 session 存储。  默认值是true  建议设置成true    cookie: {        maxAge:5000    /*过期时间*/    },   /*secure https这样的情况才可以访问cookie*/    //设置过期时间比如是30分钟,只要游览页面,30分钟没有操作的话在过期        rolling:true //在每次请求时强行设置 cookie,这将重置 cookie 过期时间(默认:false)}))

七、表单事件

Form 对象属性:

属性 描述

action接收请求的URLelements表单中的所有控件元素集合length表单控件的个数enctype编码类型 例:enctype=“multipart/form-data”name表单元素名称Form 对象方法:

方法 描述

reset()把表单的所有输入元素重置为它们的默认值。submit()提交表单。Form 对象事件:

事件 描述

onreset在重置表单元素之前调用。onsubmit在提交表单之前调用。表单控件的属性:

属性 描述

value获取和设置值disabled获取或设置表单控件是否禁用值为true或 falsetype读取表单控件的类型form所在表单元素对象readOnly控件只读属性 Boolean 不能更改只能复制和读取name获取与设置name字段名表单控件的事件:

事件 描述

onblur当失去焦点的时候onfocus当获取焦点的时候onchange当内容改变并失去焦点的时候oninput在用户输入时触发表单控件的方法:

方法 描述

focus()获得焦点blur()失去焦点select()选择文本控件中的所有文本内容

以上就是总结Node.js模块开发及常用技巧分享的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/835482.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月27日 10:06:36
下一篇 2025年11月27日 10:12:49

相关推荐

  • Uniapp 中如何不拉伸不裁剪地展示图片?

    灵活展示图片:如何不拉伸不裁剪 在界面设计中,常常需要以原尺寸展示用户上传的图片。本文将介绍一种在 uniapp 框架中实现该功能的简单方法。 对于不同尺寸的图片,可以采用以下处理方式: 极端宽高比:撑满屏幕宽度或高度,再等比缩放居中。非极端宽高比:居中显示,若能撑满则撑满。 然而,如果需要不拉伸不…

    2025年12月24日
    400
  • 如何让小说网站控制台显示乱码,同时网页内容正常显示?

    如何在不影响用户界面的情况下实现控制台乱码? 当在小说网站上下载小说时,大家可能会遇到一个问题:网站上的文本在网页内正常显示,但是在控制台中却是乱码。如何实现此类操作,从而在不影响用户界面(UI)的情况下保持控制台乱码呢? 答案在于使用自定义字体。网站可以通过在服务器端配置自定义字体,并通过在客户端…

    2025年12月24日
    800
  • 如何在地图上轻松创建气泡信息框?

    地图上气泡信息框的巧妙生成 地图上气泡信息框是一种常用的交互功能,它简便易用,能够为用户提供额外信息。本文将探讨如何借助地图库的功能轻松创建这一功能。 利用地图库的原生功能 大多数地图库,如高德地图,都提供了现成的信息窗体和右键菜单功能。这些功能可以通过以下途径实现: 高德地图 JS API 参考文…

    2025年12月24日
    400
  • 如何使用 scroll-behavior 属性实现元素scrollLeft变化时的平滑动画?

    如何实现元素scrollleft变化时的平滑动画效果? 在许多网页应用中,滚动容器的水平滚动条(scrollleft)需要频繁使用。为了让滚动动作更加自然,你希望给scrollleft的变化添加动画效果。 解决方案:scroll-behavior 属性 要实现scrollleft变化时的平滑动画效果…

    2025年12月24日
    000
  • 如何为滚动元素添加平滑过渡,使滚动条滑动时更自然流畅?

    给滚动元素平滑过渡 如何在滚动条属性(scrollleft)发生改变时为元素添加平滑的过渡效果? 解决方案:scroll-behavior 属性 为滚动容器设置 scroll-behavior 属性可以实现平滑滚动。 html 代码: click the button to slide right!…

    2025年12月24日
    500
  • 如何选择元素个数不固定的指定类名子元素?

    灵活选择元素个数不固定的指定类名子元素 在网页布局中,有时需要选择特定类名的子元素,但这些元素的数量并不固定。例如,下面这段 html 代码中,activebar 和 item 元素的数量均不固定: *n *n 如果需要选择第一个 item元素,可以使用 css 选择器 :nth-child()。该…

    2025年12月24日
    200
  • 使用 SVG 如何实现自定义宽度、间距和半径的虚线边框?

    使用 svg 实现自定义虚线边框 如何实现一个具有自定义宽度、间距和半径的虚线边框是一个常见的前端开发问题。传统的解决方案通常涉及使用 border-image 引入切片图片,但是这种方法存在引入外部资源、性能低下的缺点。 为了避免上述问题,可以使用 svg(可缩放矢量图形)来创建纯代码实现。一种方…

    2025年12月24日
    100
  • 如何让“元素跟随文本高度,而不是撑高父容器?

    如何让 元素跟随文本高度,而不是撑高父容器 在页面布局中,经常遇到父容器高度被子元素撑开的问题。在图例所示的案例中,父容器被较高的图片撑开,而文本的高度没有被考虑。本问答将提供纯css解决方案,让图片跟随文本高度,确保父容器的高度不会被图片影响。 解决方法 为了解决这个问题,需要将图片从文档流中脱离…

    2025年12月24日
    000
  • 为什么 CSS mask 属性未请求指定图片?

    解决 css mask 属性未请求图片的问题 在使用 css mask 属性时,指定了图片地址,但网络面板显示未请求获取该图片,这可能是由于浏览器兼容性问题造成的。 问题 如下代码所示: 立即学习“前端免费学习笔记(深入)”; icon [data-icon=”cloud”] { –icon-cl…

    2025年12月24日
    200
  • 如何利用 CSS 选中激活标签并影响相邻元素的样式?

    如何利用 css 选中激活标签并影响相邻元素? 为了实现激活标签影响相邻元素的样式需求,可以通过 :has 选择器来实现。以下是如何具体操作: 对于激活标签相邻后的元素,可以在 css 中使用以下代码进行设置: li:has(+li.active) { border-radius: 0 0 10px…

    2025年12月24日
    100
  • 如何模拟Windows 10 设置界面中的鼠标悬浮放大效果?

    win10设置界面的鼠标移动显示周边的样式(探照灯效果)的实现方式 在windows设置界面的鼠标悬浮效果中,光标周围会显示一个放大区域。在前端开发中,可以通过多种方式实现类似的效果。 使用css 使用css的transform和box-shadow属性。通过将transform: scale(1.…

    2025年12月24日
    200
  • 为什么我的 Safari 自定义样式表在百度页面上失效了?

    为什么在 Safari 中自定义样式表未能正常工作? 在 Safari 的偏好设置中设置自定义样式表后,您对其进行测试却发现效果不同。在您自己的网页中,样式有效,而在百度页面中却失效。 造成这种情况的原因是,第一个访问的项目使用了文件协议,可以访问本地目录中的图片文件。而第二个访问的百度使用了 ht…

    2025年12月24日
    000
  • 如何用前端实现 Windows 10 设置界面的鼠标移动探照灯效果?

    如何在前端实现 Windows 10 设置界面中的鼠标移动探照灯效果 想要在前端开发中实现 Windows 10 设置界面中类似的鼠标移动探照灯效果,可以通过以下途径: CSS 解决方案 DEMO 1: Windows 10 网格悬停效果:https://codepen.io/tr4553r7/pe…

    2025年12月24日
    000
  • 使用CSS mask属性指定图片URL时,为什么浏览器无法加载图片?

    css mask属性未能加载图片的解决方法 使用css mask属性指定图片url时,如示例中所示: mask: url(“https://api.iconify.design/mdi:apple-icloud.svg”) center / contain no-repeat; 但是,在网络面板中却…

    2025年12月24日
    000
  • 如何用CSS Paint API为网页元素添加时尚的斑马线边框?

    为元素添加时尚的斑马线边框 在网页设计中,有时我们需要添加时尚的边框来提升元素的视觉效果。其中,斑马线边框是一种既醒目又别致的设计元素。 实现斜向斑马线边框 要实现斜向斑马线间隔圆环,我们可以使用css paint api。该api提供了强大的功能,可以让我们在元素上绘制复杂的图形。 立即学习“前端…

    2025年12月24日
    000
  • 图片如何不撑高父容器?

    如何让图片不撑高父容器? 当父容器包含不同高度的子元素时,父容器的高度通常会被最高元素撑开。如果你希望父容器的高度由文本内容撑开,避免图片对其产生影响,可以通过以下 css 解决方法: 绝对定位元素: .child-image { position: absolute; top: 0; left: …

    2025年12月24日
    000
  • CSS 帮助

    我正在尝试将文本附加到棕色框的左侧。我不能。我不知道代码有什么问题。请帮助我。 css .hero { position: relative; bottom: 80px; display: flex; justify-content: left; align-items: start; color:…

    2025年12月24日 好文分享
    200
  • 前端代码辅助工具:如何选择最可靠的AI工具?

    前端代码辅助工具:可靠性探讨 对于前端工程师来说,在HTML、CSS和JavaScript开发中借助AI工具是司空见惯的事情。然而,并非所有工具都能提供同等的可靠性。 个性化需求 关于哪个AI工具最可靠,这个问题没有一刀切的答案。每个人的使用习惯和项目需求各不相同。以下是一些影响选择的重要因素: 立…

    2025年12月24日
    300
  • 如何用 CSS Paint API 实现倾斜的斑马线间隔圆环?

    实现斑马线边框样式:探究 css paint api 本文将探究如何使用 css paint api 实现倾斜的斑马线间隔圆环。 问题: 给定一个有多个圆圈组成的斑马线图案,如何使用 css 实现倾斜的斑马线间隔圆环? 答案: 立即学习“前端免费学习笔记(深入)”; 使用 css paint api…

    2025年12月24日
    000
  • 如何使用CSS Paint API实现倾斜斑马线间隔圆环边框?

    css实现斑马线边框样式 想定制一个带有倾斜斑马线间隔圆环的边框?现在使用css paint api,定制任何样式都轻而易举。 css paint api 这是一个新的css特性,允许开发人员创建自定义形状和图案,其中包括斑马线样式。 立即学习“前端免费学习笔记(深入)”; 实现倾斜斑马线间隔圆环 …

    2025年12月24日
    100

发表回复

登录后才能评论
关注微信