node.js入门笔记
基本名词概念
同步:
当一个同步调用发出后,调用者要一直等待返回消息(或者调用结果)通知后,才能进行后续的执行
异步:
当一个异步过程调用发出后,调用者不能立刻得到返回消息(结果)。在调用结束之后,通过消息回调来通知调用者是否调用成功。
阻塞:
阻塞调用是指调用结果返回之前,当前线程会被挂起,一直处于等待消息通知,不能够执行其他业务,函数只有在得到结果之后才会返回。
非阻塞:
非阻塞和阻塞的概念相对应,指在不能立刻得到结果之前,该函数不会阻塞当前线程,而会立刻返回。
同步和异步指的是线程之间的关系,阻塞和非阻塞指的是同一线程的状态
I/O:
一般指通过网络或存储介质读取或写入数据。
回调:
指函数在运行完成后的执行部分,用于异步的实现
路由:
URL到函数的映射。接收 HTTP 请求中的参数,然后决定要执行的代码
中间件:
请求与处理的中间过程,比如解析json请求为对象
基础知识
路由
路由直接定义:
1 | //app.all()用于响应任何http方法 |
1 | //app.get()接收GET方法的http访问 |
路由外部导入:
1 | //app.use()用于主文件导入路由 |
1 | //路由文件导出 |
事件 / 事件监听(EventEmitter)
Node.js 所有的异步 I/O 操作在完成时都会发送一个事件到事件队列。
Node.js 里面的许多对象都会分发事件:一个 net.Server 对象会在每次有新连接时触发一个事件, 一个 fs.readStream 对象会在文件被打开的时候触发一个事件。 所有这些产生事件的对象都是 events.EventEmitter 的实例。
导入 events.Emitter
1 | // 引入 events 模块 |
开启事件监听
1 | event.on('some_event', function() { |
触发事件监听
1 | event.emit('some_event'); |
req 和 res 对象的常用属性和方法
req常用属性
1 | req.ip //请求来源的ip |
res常用方法
1 | res.append() //添加指定内容的响应头,如res.append('Set-Cookie', 'foo=bar; Path=/; HttpOnly'); |
详细参数介绍见Node.js res 对象 - 蝴蝶教程 (jc2182.com)
参考node js中的req.body,req.query,req.params取参数 - Diamond蚊子 - 博客园 (cnblogs.com)
中间件(middleware)
[MDN web doc](Express/Node 入门 - 学习 Web 开发 | MDN (mozilla.org)): 可以使用
app.use()
或app.add()
将一个中间件函数添加至处理链中,这取决于中间件是应用于所有响应的,还是应用于特定 HTTP 动词(GET
,POST
等)响应的。可以为两种情况指定相同的路由,但在调用app.use()
时路由可以省略。
调用中间件
1 | example: |
错误处理中间件
1 | app.use((err, req, res, next) => { //错误处理的中间件有err, req, res, next四个参数 |
内置中间件和三方中间件
内置中间件(Built-in middleware)指导入模块时自带的中间件
比如express提供了express.static express.json 和 express.urlencoded 两个中间件,其中express.static用于托管静态html或图像之类的文件内容,express.json用于解析json请求,express用于解析url编码的内容,后两者在express 5.14
后添加
三方中间件(Third-party middleware)指第三方编写的中间件
三方中间件需要与主要模块兼容,比如下面的cookie-parser
1 | var express = require('express') |
模板渲染
设置模板
1 | // 设置包含模板的文件夹('views') |
使用模板
1 | app.get('/', (req, res) => { |
文件系统 fs
1 | var fs = require("fs") |
文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()。
异步的方法函数最后一个参数为回调函数,回调函数的第一个参数包含了错误信息(error)。
fs 的常用方法
fs的同步方法名基本都是其异步方法名+Sync
readFile:
1 | fs.readFile('./public/1.html', 'utf8' , (err, data) => { //异步函数一定要指定回调函数 |
1 | 其他: |
流Stdin Stdout Stderr
stdout
,stdin
, 和stderr
是标准的流,当程序执行时,它们在程序和环境之间互连输入和输出通信通道。
每个进程初始化时都有三个开放的文件描述符,分别称为stdin
、stdout
、stderr
,也被称作标准流 。
为一个进程启动了一组三个标准流,我们可以通过Node.js中的process
对象访问它们。
- stdin: 输入流
- stdout: 输出流
- stderr: 错误流
控制台与自己初始事件的标准流相绑定,比如console.log()
就实现了process.stdout.out()
因而想要创建其他进程输出到控制台时可以使用child.stdout.pipe(process.stdout)
,将输出流绑定到控制台
stderr
是默认的文件描述符 进程可以在其中写入错误信息,以避免管道末端的命令可能无法理解。
除了建立管道之外,还可以通过子进程和当前进程共用同一stdio
的方式来实现
1 | const { spawn } = require('child_process'); |
stdio选项用于配置父进程和子进程之间建立的管道,由于stdio管道有三个(stdin, stdout, stderr)因此stdio的三个可能的值其实是数组的一种简写
子进程控制
1 | child.stdin.write() //向子进程输入内容 |
参考
[Difference between console.log and process.stdout.write in NodeJS (tutorialspoint.com)](https://www.tutorialspoint.com/difference-between-console-log-and-process-stdout-write-in-nodejs#:~:text=Both the methods – console.log and process.stdout.write have,difference in the way they execute these tasks.)
在Node.js中使用stdout、stdin和stderr的方法 - 掘金 (juejin.cn)
子进程 child_proccess
1 | const cp = require('child_process'); |
freecodecamp: 单一进程总是会受到负载限制,子进程是实现高效率的一种办法
child_process提供了几种创建子进程的方式
异步方式:spawn、exec、execFile、fork
同步方式:spawnSync、execSync、execFileSync
.exec()
、.execFile()
、.fork()
底层都是通过.spawn()
实现的。
.exec()
、execFile()
额外提供了回调,当子进程停止的时候执行。
child_process.spawn(command[, args][, options])
child_process.exec(command[, options][, callback])
child_process.execFile(file[, args][, options][, callback])
child_process.fork(modulePath[, args][, options])
exec与execFile
exec
创建一个shell,在其中执行命令,提供stdio回调
1 | exec('ls -al', function(error, stdout, stderr){ |
execFile
不创建新的shell,与exec
相似
调用python解释器
执行文件并输出结构:
1 | const { execFile, execFileSync } = require('child_process'); |
exec与execFile之间的差异
[nodejs.cn: ](在 Windows 上衍生 .bat 和 .cmd 文件 | Node.js API 文档 (nodejs.cn))
child_process.exec()
和child_process.execFile()
之间区别的重要性可能因平台而异。 在 Unix 类型的操作系统(Unix、Linux、macOS)上,child_process.execFile()
可以更高效,因为它默认不衍生 shell。 但是,在 Windows 上,.bat
和.cmd
文件在没有终端的情况下无法自行执行,因此无法使用child_process.execFile()
启动。
fork
modulePath
:子进程运行的模块。
参数说明:
execPath
: 用来创建子进程的可执行文件,Linux下默认是/usr/local/bin/node
。可通过execPath
来指定具体的node可执行文件路径。execArgv
: 传给可执行文件的字符串的参数列表。默认是process.execArgv
,跟父进程保持一致。silent
: 默认是false
,即子进程的stdio
从父进程继承。如果是true
,则直接pipe
向子进程的child.stdin
、child.stdout
等。stdio
: 如果声明了stdio
,则会覆盖silent
选项的设置。
例子
1 | var child_process = require('child_process'); |
控制台成功可以输出子进程的打印内容
spawn
特点:spawn 与 exec、execFile 不同的是,后两者创建时可以指定 timeout 属性设置超时时间,一旦创建的进程运行超过设定的时间将会被杀死;exec 与 execFile 不同的是,exec 适合执行已有的命令,execFile 适合执行文件;exec、execFile、fork 都是 spawn 的延伸应用,底层都是通过 spawn 实现的;
功能纯粹的方法,用法类似如下
1 | var ls = spawn('ls', ['-al'], { |
参考Nodejs进阶:如何玩转子进程(child_process) - 程序猿小卡 - 博客园 (cnblogs.com),玩转 node 子进程 — child_process - 掘金 (juejin.cn)
express框架学习
Express 是一个非常轻量的 web 应用框架,这是有意为之的,它巨大的裨益和无尽的潜能都来自第三方的库和功能。
模块导入:
1 | const express = require('express'); //导入express模块 |
1 | app.listen(3000, () => { //创建3000端口监听,即开启服务 |
express快速建站示例,命令行node +文件名运行
1 | var express = require('express'); |
express内置中间件
express.static
express.static用来托管静态文件,包括图片、CSS 以及 JavaScript 文件
1 | app.use(express.static('public')); |
然后public
文件夹下的所有文件均可通过url+文件名
的方式访问了,比如访问/public/imgaes/default.png
的访问方式即为http:ip:port/images/default.png
express.json
这是Express中的一个内置中间件函数。它使用JSON有效载荷解析传入的请求,并且基于body-parser。
返回只解析JSON并且只查看Content-Type头与type选项匹配的请求的中间件。这个解析器接受主体的任何Unicode编码,并支持gzip和deflate编码的自动膨胀(automatic inflation)。
在中间件(例如req.body)之后,一个包含解析数据的新body对象被填充到请求对象中,或者如果没有要解析的body,内容类型不匹配,或者发生了错误,则为一个空对象({})。
express.urlencode
基于body-parser
对url编码后的内容解析
express兼容中间件
MDN: Express 是高度包容的。几乎可以将任何兼容的中间件以任意顺序插入到请求处理链中,只要你喜欢。可以用单一文件或多个文件构造应用,怎样的目录结构都可以。有时候你自己都会觉得眼花缭乱!
cookie-parser
cookie-parser
用于cookie的解析,即从中获取访问者相关认证信息
导入cookie-parser
后设置res.cookie
配置信息
初始化cookie-parser
1 | app.use(cookie-parser('secret')); //设置加密密钥 |
设置cookie
1 | res.cookie("add",adds,{ signed: true, maxAge: 900000, httpOnly: true}); //由express完成 |
1 | res.cookie的配置选项 |
然后在访问中就可以通过req.cookies.<key>
访问该键值,如
1 | app.use(function (req, res, next) { |
body-parser
解析请求的body部分,提供req.body的直接访问
Reference:
node.js中express使用cookie-parser 和 cookie-session处理会话 - 怀素真 - 博客园 (cnblogs.com)