JS服务端技术—Node.js知识点锦集

2023-11-29 04:31

本文主要是介绍JS服务端技术—Node.js知识点锦集,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

【版权声明】未经博主同意,谢绝转载!(请尊重原创,博主保留追究权)
https://blog.csdn.net/m0_69908381/article/details/134544523
出自【进步*于辰的博客】

接触Node.js挺长时间了,工作也经常使用,只是接口开发更倾向于业务的梳理,对基础要求反而不高。就是,参考前辈的代码写路由,工作重心在接口代码。
基础不牢固,不仅影响工作效率,而且不利于个人发展,所以近期开始恶补JS服务端技术的基础,就从Node.js开始。

文章目录

  • 1、关于 Buffer
  • 2、fs模块
    • 2.1 读文件
    • 2.2 写文件
  • 3、path模块
  • 4、express模块
    • 4.1 响应相关函数
    • 4.2 中间件
    • 4.3 Router
    • 4.4 解析请求体数据
    • 4.5 综合示例
  • 5、http模块
  • 6、关于静态资源无法访问问题
  • 7、关于通用设置
  • 留言

1、关于 Buffer

详述可查阅博文【02-Node.js—Buffer(缓冲器)】(转发)。
参考笔记三,P49.1。

Buffer是一种类似数组的对象,用于表示固定长度的字节序列,其本质是一段内存空间,且空间由 c + + \color{green}{c++} c++申请,每个元素占一个字节。

创建: \color{brown}{创建:} 创建:

  1. Buffer.alloc(size):创建长度为 size 的字节序列;
  2. buffer.allocUnsafe(size):同上,区别是在分配内存时不会清除旧数据(指曾使用过仍保留数据、但目前未使用的内存空间);
  3. Buffer.from(xx):xx 可以是数组、字符串或 Buffer。

说明: \color{red}{说明:} 说明:
1、由于每个元素占一个字节,故alloc(size)allocUnsafe(size)创建的字节序列共包含 size 个字节。
示例:

var buf = Buffer.alloc(10)
// 打印buf:<Buffer 00 00 00 00 00 00 00 00 00 00>

规定以16进制的格式进行显示,00(16进制)是0000 0000(二进制),共10个元素。

2from(xx)创建的字节序列所占字节数由 xx 决定。
示例1。(xx是数组)

var arr = [2, 0, 2, 3]
var buf = Buffer.from(arr)
// 打印buf:<Buffer 02 00 02 03>

数字占一个字节,故长度为4
2(数字,十进制)是02(16进制)。

示例2.。(xx是字符串)

var buf = Buffer.from('2023')
// 打印buf:<Buffer 32 30 32 33>

为何buf[0]32?因为此时的2不是数字,而是字符。
'2' A S C L L 码 \color{blue}{ASCLL码} ASCLL50,转换成16进制就是32

示例3。(xx是字符串)

var buf = Buffer.from('汉字')
// 打印buf:<Buffer e6 b1 89 e5 ad 97>

是不是有点懵?因为Buffer采用utf-8编码,一个汉字占3个字节,故用三个元素表示一个汉字。
改一下。

var buf = Buffer.from('汉字')
buf[0] = 97 + 7// 'h'的ASCLL码
buf[1] = 97
buf[2] = 97 + 13
console.log(buf.toString())// 打印:han字

toString()会将每个元素都转换成对应的字符,这样是不是一目了然了。
再补充一点。

var buf = Buffer.from('汉字')
buf[0] = 97 + 7 + 256// ------------------A
buf[1] = 97
buf[2] = 97 + 13
console.log(buf.toString())// 打印:han字

97 + 7'h' A S C L L 码 ASCLL码 ASCLL,再+ 256已经不是'h',为何最后还是'h'
因为Buffer规定,一个字符占一个字节。换言之,只会用一个字节来表示字符,如果字符对应的 A S C L L 码 ASCLL码 ASCLL超出一个字节(8位)的表示范围(255),超出的部分会被丢弃。
256对应的二进制是1 00000000,即需要两个字节,则第一个字节舍去,剩下0000 0000,为0(十进制)。

示例4。(xx 是Buffer

var buf1 = Buffer.from([2, 0, 2, 3])
var buf2 = Buffer.from(buf1)
// 打印buf:<Buffer 02 00 02 03>

与示例1相同。

2、fs模块

详述可查阅博文【03-Node.js—fs模块】(转发)。
参考笔记三,P50、P51。

fs模块是Node.js的内置模块,负责与文件系统的交互。

2.1 读文件

函数:

  1. 异步读取:readFile(path[, options], (err, content) => {})
  2. 同步读取:var content = readFileSync(path[, options])
  3. 流式读取:(1)创建读取流:createReadStream(path[, options]);(2)通过'data''end'事件读取。

注:options是读取配置,如:'utf-8',否则读取结果为二进制序列。

2.2 写文件

函数:

  1. 异步写入:writeFile(path, data[, options], err => {})
  2. 同步写入:writeFileSync(path, data[, options]),返回undefinied
  3. 流式写入:(1)创建写入流:createWriteStream(path[, options]);(2)写入:write(data)
  4. 附加写入:appendFile() / appendFileSync(),参数同上。

注:options是写入配置,如:{flag: 'a'}表示附加写入(暂不理解)。

3、path模块

详述可查阅博文【04-Node.js—path模块】(转发)。
参考笔记三,P51。

函数:

  1. 解析路径:resolve(path),path 前常附加当前目录__dirname
  2. 返回文件后缀:extname(path)

4、express模块

详述可查阅博文【09-Node.js—express框架】(转发)。
参考笔记三,P46、P50、P51。

express模块是基于Node.js的web应用开发框架,主要用于搭建js服务器。

4.1 响应相关函数

  1. 重定向:res.redirect(url)
  2. 响应文件:res.download(path),path 可以是绝对 / 相对路径,此函数是基于fs.readFile()res.end()的封装;
  3. 以json字符串作为响应体:res.json({})
  4. 设置响应体:res.send(),此函数是基于res.end()(http模块)的封装,可响应任何类型,且只保留数据部分,如会将str最外层的''/""省略。
    注意: \color{red}{注意:} 注意:此函数是设置响应体,也是响应。虽是响应,但请求处理未结束,也由于是响应,故在其后不能再做响应配置,如:res.write()(http模块)、res.set()(见第7项);
  5. 响应文件:res.sendFile(path.resolve(__dirname + path))。path 必须是绝对路径,故拼接了__dirname

4.2 中间件

1 、路由中间件 \color{green}{1、路由中间件} 1、路由中间件
“路由中间件”表现为具有三个参数(req, res, next)的函数,用于封装路由公共代码(匹配路由前的操作),故需要置于所有路由之前(即中间件之前的路由不会执行中间件,因为路由匹配至上而下),且必须调用next()才能执行路由(暂不知next是什么)。

2 、静态资源中间件 \color{blue}{2、静态资源中间件} 2、静态资源中间件
设置项目根目录为目录express.static(目录)

注意: \color{red}{注意:} 注意:中间件必须使用ser.use()引入。

4.3 Router

Router是一个完整的中间件和路由系统,可看作是一个小型的js服务器(当然并不是js服务器,故需要引入到js服务器中使用)。

使用步骤:

  1. 创建路由:var rou = express.Router()
  2. 配置路由(与js服务器相同);
  3. 开放接口:module.exports = rou
  4. 引入:ser.use(require(Router路径)),路径必须是相对路径,且必须采用./格式。

注意:

  1. 若使用 Router,必须在 Router 的路由的适当位置调用next()(先在路由回调函数上添加next参数)。因为 Router 是子服务,一般使用 Router 时,主服务中肯定也有路由,如果不调用next(),则不会检索主路由;
  2. 留言: \color{red}{留言:} 留言:Router 没有跨域问题,原因未知。

4.4 解析请求体数据

debug 一下,就可以发现req对象具有三个属性,query(封装请求行数据)、params(封装动态请求数据,暂不清楚)、body(封装请求体数据)。
假设body = {id: 2023},则通过req.body.idreq.body['id']即可获取参数id的值,之所以能获取到,是因为body中数据的格式是json。换言之,若请求数据的格式不是json,就不一定能解析成功。
这时,可以使用body-parser模块进行辅助解析。

步骤:

  1. (1)若请求数据封装的方式是x-www-form-urlencoded,构造对象:var urlParser = bodyParser.urlencoded({extended: false});(2)若封装方式是json,构造对象:var jsonParser = bodyParser.json()
  2. 将路由的第2个参数设置为urlParser

留言: \color{green}{留言:} 留言:我尝试了很多方法进行模拟测试,ajax、postman、form等等,可不知为何,req对象中始终没有body属性(js服务端使用vscode开发),故根本无法测试,所以只能请大家自行测试领悟了。

4.5 综合示例

先言: \color{red}{先言:} 先言:代码稍微有点长,一是为了尽量多使用express模块的函数,做个示例;二是为了使功能稍微丰满一点。大家阅读的时候,直接跳过与业务相关的代码,留意以上四个知识点相关的部分就OK。

1、主服务代码。

const express = require('express')
const bodyParser = require('body-parser')
const path = require('path')const ser = express()// 构建服务
// 引入静态资源中间件,
ser.use(express.static('./'))// 设置项目根目录为当前目录// 引入路由中间件
ser.use((req, res, next) => {res.set('access-control-allow-origin', 'http://127.0.0.1:5501')// 跨域配置next()
})// 引入Router
ser.use(require('./r1'))// Router与当前文件同目录,文件名是 r1.jsvar users = [{id: 1,name: '进步',pass: '2023'}, {id: 2,name: '于辰',pass: '2021'}
]ser.get('/g1', (req, res) => {var id = req.query.useridvar result = users.find(item => {if (item.id == id) {res.json({id: id,user: item.name,pass: item.pass})return true}})if(!result)// 未找到res.send('<h1>此账号异常</h1>')
})var jsonParser = bodyParser.json()
ser.post('/p1', jsonParser, (req, res) => {var user = req.body.usernamevar pass = req.body.passwordvar result = users.find(item => {if(item.name == user && item.pass == pass) {// 账号、密码正确,返回用户界面res.sendFile(path.resolve(__dirname + '/userinfo.html'))}})if(!result) {// 账号、密码错误,返回首页res.download('index.html')}
})ser.all('*', (req, res) => {res.send('<h1>not found route</h1>')
})// 启动服务,监听8081端口
ser.listen(8081, () => {console.log('created')
})

2、Router代码

const express = require('express')
const bodyParser = require('body-parser')let rou = express.Router()// 创建Router// Router是完整的中间件和路由系统,故也可在此创建路由中间件
// ser.use((req, res, next) => {
//     res.set('access-control-allow-origin', 'http://127.0.0.1:5501')
//     next()
// })rou.get('/rou/g1', (req, res) => {var id = req.query.userid
})var urlParser = bodyParser.urlencoded({extended: false})
rou.post('/rou/p1', urlParser, (req, res) => {var user = req.body.usernamevar pass = req.body.password
})rou.all('rou/*', (req, res, next) => {// 路由检索自上而下,若匹配此路由,说明此Router中没有”有效“匹配的路由,// 则调用 next() ”跳出“此Router,去主服务检索路由next()
})module.exports = rou// 开放接口

5、http模块

详述可查阅博文【05-Node.js—http模块】(转发)。
参考笔记三,P50。

http模块是一个Node.js中与HTTP协议对接的模块,用于搭建HTTP服务,或者说用于搭建js服务器。

相关操作: \color{red}{相关操作:} 相关操作:
1、创建http服务:http.createServer((req, res) => {})

2、获取请求行数据。
方法一:

// 由于http服务封装的req对象中没有query、params属性,
// 故需要使用url模块将req.url进行构造,从中获取请求行数据
const u = require('url')
var url = u.parse(req.url)// url中包含query属性,但其中数据的格式是字符串,故下行代码报错,无法获取
var ID  = url.query.userid// 重新构造
var url = u.了parse(req.url, true)
// 这样格式就转化成了js对象

方法二:

// 原理同上,只是换用内置对象URL进行构造,
// 前缀'http...'是任意的。不过,出于业务考虑,应与客户端相同
var url = new URL(req.url, 'http://127.0.0.1:5500')// URL对象中请求行数据封装在属性searchParams中,而不是query
// searchParams中数据的格式不是js对象,需要调用get()获取
var id = url.searchParams.get('id')

3、获取请求体数据。

// req对象中同样没有body属性,需要使用'data'和'end'事件进行获取
var bodyData
req.on('data', temp => {// temp的类型是String,故直接拼接bodyData += temp
})
req.on('end', () => {// bodyData是String,故如此无法获取,var id = bodyData.userid
})

我暂且也不知如何解析:String → js对象,大家自行补充了。

留言: \color{orange}{留言:} 留言:我未查阅资料的原因:(1)在上面express模块的示例中我提起过,不知为何req对象中没有body属性,故我无法测试;(2)express模块是基于http模块的封装,使用express模块搭建的js服务器更强大。

4、设置响应头时,若有多个值,需使用数组。

5res.write(str)需与res.end(str)连用。其中,res.write()用于附加响应。

6、当使用live-server打开html文件时,项目根目录为当前html文件所在目录。

留言: \color{brown}{留言:} 留言:这一点我还不太理解,至少我测试http://localhost:8081/1.jpg时仍然访问不到图片(1.jpg与当前html文件同目录)。无妨,解决办法往下看。。。

6、关于静态资源无法访问问题

关于这个问题,相关描述在博文【05-Node.js—http模块】(转发)的第4.5项,找到其中“我们该如何解决?”那一段。
参考笔记三,P49.3。

悄咪咪的告诉大家,其实在当时学习http模块的时候,一开始我是没有注意这个细节的,因为觉得莫名其妙。“对路径进行判断”,我根本无法理解其中用意(自然也没有特别去测试),所以“撇开”了。
可后来想到博主既然会用那么一定篇幅来阐述这个问题,说明有一定重要性,于是按照博主的思路具体测试了一下,终于明白了,步入正题。。。

这个问题出现的场合:

  1. 上面http模块中项目根目录无效导致无法访问静态资源;
  2. js服务器响应html文件,文件内css、js、img等静态资源无效或无法访问。(这就是那位博主所述的情况)

为了让大家充分理解,我逐步说明。。。

首先,若客户端请求的是图像文件,且正常响应,会无效吗?答案是 N O \color{red}{NO} NO,除非响应有问题。比如:服务器未将图像的所有信息(二进制)响应,那么此图像肯定无法正常显示。(一般不会有这种操作)
然后,若客户端请求的是css、js等文件,同样正常响应,会无效吗?也是 N O \color{red}{NO} NO。这种情况下即便响应不完整,也不会无效,因为是一并解释。

那为何无效或无法访问? \color{grey}{那为何无效或无法访问?} 那为何无效或无法访问?
二种情况:

  1. 客户端处理响应时调用的是text(),而不是html()(以 jq 为例),以字符串的方式处理响应内容,自然无法识别标签(如:<script>),故无效;
  2. 找不到静态资源。

若是第一种情况,调用html()即可。

那为何找不到资源? \color{grey}{那为何找不到资源?} 那为何找不到资源?
走到这一步,客户端已经可以正常处理响应,无论html、css、js还是img,故原因是:

  1. 访问路径有误;
  2. 服务器响应有误。

因为已经可以正常解析响应的html文件,即静态资源标签的src属性有效。

在解析html文件时,会同时根据src属性的路径向服务器发起请求。

因此,这种情况下src必须是完整路径,如:http://127.0.0.1:8081/1.jpg,这样才有可能找到文件。

完整路径能找到静态资源吗? \color{grey}{完整路径能找到静态资源吗?} 完整路径能找到静态资源吗?
若js服务器由express模块搭建,只要配置好项目根目录(静态资源中间件),就可以直接找到静态资源。
若js服务器由http模块搭建,由于无法配置项目根目录,故只能由路由对完整路径进行处理,从而返回静态资源(那位博主说“对路径进行判断”就是这个意思)。

示例:

const httpSer = http.createServer((req, res) => {if (req.url == '/1.jpg') {fs.readFile(__dirname + url, (err, data) => {res.end(data)})return}var data = fs.readFileSync(__dirname + '/index.html')res.end(data)
})

O K ! P e r f e c t !! \color{orange}{OK!Perfect!!} OKPerfect!!http模块中项目根目录无效导致无法访问静态资源的问题也解决了。

7、关于通用设置

参考笔记三,P49.2/4。

“通用设置”指不同模块中业务相同的操作或函数。

  1. 设置状态码:res.statusCode()res.status()
  2. 设置状态码描述:res.statusMessage
  3. 设置响应体:res.write()res.end()res.send()
  4. 设置响应头:res.setHeader('标头', 值)res.set('标头', 值)
  5. 获取请求头:req.headers.refererreq.get('referer')
  6. (就列举这些哈,其他操作或函数不常用或者通过debug就可以知晓,以名达意。)

注:

  1. “或”前操作或函数属http模块,后属express模块,且express模块是基于http模块的封装(express模块兼容http模块);
  2. res.end()res.send()都是设置响应体的末操作,故其后不能再做响应配置。

留言

本人的核心语言是Java,故有时倾向于以Java的思想进行阐述,这可能会给向前端发展的博友们的阅读带来不适。并且,由于本文相当于是我系统学习Node.js的笔记,也基于我的Java功底,所以有些阐述不会那么详细。
不过,Java作为一种强类型的编程语言,我的阐述会很严谨,所以需要大家在阅读时多一点耐心。


本文持续更新中。。。

这篇关于JS服务端技术—Node.js知识点锦集的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/431447

相关文章

JS常用组件收集

收集了一些平时遇到的前端比较优秀的组件,方便以后开发的时候查找!!! 函数工具: Lodash 页面固定: stickUp、jQuery.Pin 轮播: unslider、swiper 开关: switch 复选框: icheck 气泡: grumble 隐藏元素: Headroom

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

【专题】2024飞行汽车技术全景报告合集PDF分享(附原数据表)

原文链接: https://tecdat.cn/?p=37628 6月16日,小鹏汇天旅航者X2在北京大兴国际机场临空经济区完成首飞,这也是小鹏汇天的产品在京津冀地区进行的首次飞行。小鹏汇天方面还表示,公司准备量产,并计划今年四季度开启预售小鹏汇天分体式飞行汽车,探索分体式飞行汽车城际通勤。阅读原文,获取专题报告合集全文,解锁文末271份飞行汽车相关行业研究报告。 据悉,业内人士对飞行汽车行业

在JS中的设计模式的单例模式、策略模式、代理模式、原型模式浅讲

1. 单例模式(Singleton Pattern) 确保一个类只有一个实例,并提供一个全局访问点。 示例代码: class Singleton {constructor() {if (Singleton.instance) {return Singleton.instance;}Singleton.instance = this;this.data = [];}addData(value)

金融业开源技术 术语

金融业开源技术  术语 1  范围 本文件界定了金融业开源技术的常用术语。 本文件适用于金融业中涉及开源技术的相关标准及规范性文件制定和信息沟通等活动。

Node.js学习记录(二)

目录 一、express 1、初识express 2、安装express 3、创建并启动web服务器 4、监听 GET&POST 请求、响应内容给客户端 5、获取URL中携带的查询参数 6、获取URL中动态参数 7、静态资源托管 二、工具nodemon 三、express路由 1、express中路由 2、路由的匹配 3、路由模块化 4、路由模块添加前缀 四、中间件

EasyPlayer.js网页H5 Web js播放器能力合集

最近遇到一个需求,要求做一款播放器,发现能力上跟EasyPlayer.js基本一致,满足要求: 需求 功性能 分类 需求描述 功能 预览 分屏模式 单分屏(单屏/全屏) 多分屏(2*2) 多分屏(3*3) 多分屏(4*4) 播放控制 播放(单个或全部) 暂停(暂停时展示最后一帧画面) 停止(单个或全部) 声音控制(开关/音量调节) 主辅码流切换 辅助功能 屏

AI(文生语音)-TTS 技术线路探索学习:从拼接式参数化方法到Tacotron端到端输出

AI(文生语音)-TTS 技术线路探索学习:从拼接式参数化方法到Tacotron端到端输出 在数字化时代,文本到语音(Text-to-Speech, TTS)技术已成为人机交互的关键桥梁,无论是为视障人士提供辅助阅读,还是为智能助手注入声音的灵魂,TTS 技术都扮演着至关重要的角色。从最初的拼接式方法到参数化技术,再到现今的深度学习解决方案,TTS 技术经历了一段长足的进步。这篇文章将带您穿越时

系统架构设计师: 信息安全技术

简简单单 Online zuozuo: 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo 简简单单 Online zuozuo :本心、输入输出、结果 简简单单 Online zuozuo : 文章目录 系统架构设计师: 信息安全技术前言信息安全的基本要素:信息安全的范围:安全措施的目标:访问控制技术要素:访问控制包括:等保

两个月冲刺软考——访问位与修改位的题型(淘汰哪一页);内聚的类型;关于码制的知识点;地址映射的相关内容

1.访问位与修改位的题型(淘汰哪一页) 访问位:为1时表示在内存期间被访问过,为0时表示未被访问;修改位:为1时表示该页面自从被装入内存后被修改过,为0时表示未修改过。 置换页面时,最先置换访问位和修改位为00的,其次是01(没被访问但被修改过)的,之后是10(被访问了但没被修改过),最后是11。 2.内聚的类型 功能内聚:完成一个单一功能,各个部分协同工作,缺一不可。 顺序内聚: