Skip to content

Node

Node.js 是一个能够在服务器端运行 JavaScript 的运行时环境,具有高性能和可扩展性,适用于构建各种类型的网络应用程序。

npm 与包

npm 命令

bash
npm -v  #查看版本号

npm init  #手动初始化项目
npm init -y  #自动初始化项目

npm install #一键安装package.json所有依赖包
npm i #简写

npm install 包名 参数  #安装包
npm i 包名 参数  #简写
#参数:--save 或 -S 安装在生产环境
#参数:--save-dev 或 -D 安装开发环境
#参数:-g 表示全局安装 
npm i 包名@版本号  #安装指定版本号的包

npm uninstall 包名 参数  #卸载包
npm uni 包名  #简写

npm config list # 查看所有 npm 配置信息

npm list  #查看安装的所有项目包
npm list -g #查看安装的所有全局包

npm publish  #发布包
npm login #登录 npm 账户
npm logout #登出 npm 账户

npm update 包名 #更新包 (更新包 也不会跨大版本)
npm outdate  #检查包是否已经过时

npm info 包名  #包详细信息
npm info 包名 version  #获取包最新版本

npm run <scriptName>  #运行package.json中定义的script命令

package.json 文件

json
{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": [],
  "devDependencies": []
}
  • name:项目名称
  • version:项目版本号
  • description:项目描述
  • main:项目的主入口文件路径,通常是一个 JavaScript 文件
  • scripts:定义了一些脚本命令
  • keywords:项目的关键字列表
  • author:项目作者的信息
  • license:项目的许可证类型
  • dependencies:项目生产环境中所依赖的包的列表
  • devDependencies:项目开发环境中所需要的包的列表

下包镜像源

切换下包镜像源

bash
#查看当前的下包镜像源
npm config get registry
#将下包的镜像源切换为淘宝镜像源
npm config set registry=https://registry.npmmirror.com/

TIP

常用下包镜像源地址

nrm 管理工具

为了更方便的切换下包镜像源,可以安装 nrm 工具,利用 nrm 提供的终端命令,可以快速查看和切换下包镜像源。

bash
#通过npm安装nrm工具
npm i nrm -g
#查看所有可用的镜像源
nrm ls
#将下包镜像源切换为taobao镜像
nrm use taobao

包的分类

项目包

安装到项目的 node_modules 目录中的包,都是项目包。

项目包分为 两类,分别是:

  • 开发依赖包:被记录到 devDependencies 节点中的包,只在开发期间会用到
  • 核心依赖包:被记录到 dependencies 节点中的包,在开发期间和项目上线之后 都会用到
bash
#开发依赖包
npm i 包名 -D
#核心依赖包
npm i 包名

全局包

在执行 npm install 命令时,如果提供了-g 参数,则会把包安装为全局包。 全局包会被安装到 C:\Users\89315\AppData\Roaming\npm\node_modules 目录下。

bash
#全局安装指定的包
npm i 包名 -g
#卸载全局安装的包
npm uninstall 包名 -g

TIP

  • 只有工具性质的包,都有全局安装的必要性,因为它们提供了好用的终端命令
  • 判断某个包是否需要全局安装后才能使用,具体参考官方提供的使用说明即可

npx 命令

npx 是 npm 自带的一个工具,它在 npm 5.2.0 及以上版本中提供。npx 的主要作用是执行临时安装的包中的命令,而无需事先全局安装这些包。

  • 检查要执行的命令是否在本地项目的 node_modules/.bin 目录中存在。如果存在,则直接执行该命令。
  • 如果命令在本地项目中不存在,npx 会尝试在全局 node_modules/.bin 目录中查找是否有对应的命令。如果找到了,也会直接执行该命令。
  • 如果命令在全局 node_modules/.bin 目录中也不存在,npx 会临时安装对应的包,然后执行该包中的命令。安装完成后执行命令,执行完毕后会将临时安装的包清理掉。

与 npm 区别

  • npx 用于执行临时安装的包中的命令,而不需要全局安装这些包。
  • npm 是 Node.js 包管理器,用于安装、管理和发布 JavaScript 包。
  • npm run 用于运行 package.json 中定义的脚本命令。

发布 npm 包

初始化包

  1. 新建一个包文件夹,作为包的根目录
  2. 在该文件夹中,新建如下 3 个文件:
    • package.json:包管理配置文件
    • index.js:包的入口文件
    • README.md:包的说明文档

初始化 package.json

json
{
  "name": "customPackage",
  "version": "1.0.0",
  "main": "index.js",
  "description": "包的功能描述",
  "keywords": ["keywords1", "keywords2", "keywords3"],
  "license": "ISC"
}

发布包到 npm 服务器

1.注册 npm 账号

访问 npm 官网www.npmjs.com,点击sign up 按钮进入注册界面。

2.登录 npm 账号

npm 账号注册完成后,可以在终端中执行 npm login 命令,依次输入用户名、密码、邮箱,即可登录 成功。

bash
npm login

3.把包发布到 npm 服务器上

将终端切换到包的根目录之后,运行 npm publish 命令,即可将包发布到 npm 服务器上。

bash
npm publish

注意

包名不能雷同,且必须是英文。

4.删除已发布的包

运行 npm unpublish 包名 --force 命令,即可从 npm 服务器上删除已发布的包。

bash
npm unpublish 包名 --force

TIP

  • npm unpublish 命令只能删除 72 小时以内发布的包
  • npm unpublish 删除的包在 24 小时内不允许重复发布

npm 私服

Verdaccio 是一个轻量级的私有 npm 代理/注册表,它允许你在本地搭建一个 npm 包管理服务器。使用 Verdaccio,你可以在本地网络中创建一个私有的 npm 注册表,以便在你的项目中使用内部或私有的 npm 包,或者用于测试、缓存和加速 npm 包的下载过程。

模块化

CommonJS 规范

Node 默认遵守的规范。

引入模块(require)

  • 内置模块

由 Node.js 官方提供的,例如 fs、path、http 等。

javascript
//引入内置模块
const fs = require('node:fs')

Node:ModuleName

  • 直接使用 require('fs'),需要等 node.js 将所有核心模块加载完成后才可以使用,这个可以通过 module.builtinModules 去判断是否加载完成
  • 使用 require('node:fs'),则不需要等待,可以直接调用内置模块,但是却无法使用缓存
  • 自定义模块

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

javascript
//引入用户的自定义模块,可以省略.js后缀名
const custom = require('./custom.js')
//等同于如下
const custom = require('./custom')
  • 第三方模块

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

javascript
//引入第三方模块
const moment = require('moment')
  • json 文件
js
//引入json数据
const data = require('./data.json')
  • C++扩展模块
js
//引入addon C++扩展模块 .node 文件
const nodeModule = require('./myModule.node')

模块作用域

和函数作用域类似,在自定义模块中定义的变量、方法等成员,只能在当前模块内被访问。

暴露模块

  • module.exports

在自定义模块中,可以使用 module.exports 对象,将模块内的成员共享出去,供外界使用。外界用 require()方法导入自定义模块时,得到的就是 module.exports 所指向的对象。

javascript
// 导出一个函数
module.exports = function () {
  // ...
}
  • exports

由于 module.exports 单词写起来比较复杂,为了简化向外共享成员的代码,Node 提供了 exports 对象。默认情况下,exports 和 module.exports 指向同一对象。最终共享的结果,还是以 module.exports 指向的对象为准。

javascript
// 导出多个函数
exports.function1 = function () {
  // ...
}
exports.function2 = function () {
  // ...
}

TIP

  • 时刻谨记,使用 require()模块时,得到的永远是 module.exports 指向的对象;
  • 为了防止混乱,建议不要在同一个模块中同时使用 exports 和 module.exports。

ESM 模块规范

从 Node.js 12 版本开始,你可以通过添加 .mjs 扩展名来使用 ESM 模块,或者在 package.json 中设置 "type": "module" 来启用 ESM 支持。

javascript
"type": "module"

引入模块(import)

引入模块 (import) 必须写在头部,支持引入内置模块、自定义模块、第三方模块,但默认不支持引入 json 文件。

WARNING

从 Node.js 13.2.0 版本开始,ESM 模块支持通过 import 语句直接引入 JSON 文件。

暴露模块

  • 默认暴露
js
export default {
  //object
}
  • 分别暴露
js
export const a = 1

export const obj = {
  //object
}

注意

默认暴露引入时不需要解构赋值,而分别暴露引入时需要进行解构赋值。

js
//默认暴露
import abc from './data.js'

//分别暴露
import { a } from './data.js'

CJS 和 ESM 区别

  • CJS 是基于运行时的同步加载,esm 是基于编译时的异步加载
  • CJS 是可以修改值的,esm 值并且不可修改(可读的)
  • CJS 不可以 tree shaking,esm 支持 tree shaking
  • commonjs 中顶层的 this 指向这个模块本身,而 ES6 中顶层 this 指向 undefined

全局变量

定义全局变量

在 nodejs 中使用 global 定义全局变量,在引入的文件中可以访问该变量。

js
// 只能在 Node 环境中访问,无法在 Windows 环境中访问
global.xxx = 'xxx'

// 既能在 Node 环境中访问,也能在 Windows 环境中访问
globalThis.xxx = 'xxx'

注意

由于 nodejs 中没有 DOM 和 BOM,除了这些 API,其他的 ECMAScript API 基本都能使用。

内置全局 APIs

  • __dirname :是一个全局变量,用于获取当前模块文件所在的目录的绝对路径。
  • __filename : 是一个全局变量,用于获取当前模块文件的绝对路径,包括文件名。
  • require :用于引入模块的关键字
  • exports :用于定义模块输出内容的对象
  • process :是一个全局对象,用于访问有关进程的信息和控制进程
    • process.argv: 这是一个包含命令行参数的数组。第一个元素是 Node.js 的执行路径,第二个元素是当前执行的 JavaScript 文件的路径,之后的元素是传递给脚本的命令行参数。
    • process.env: 这是一个包含当前环境变量的对象。您可以通过 process.env 访问并操作环境变量。
    • process.cwd(): 这个方法返回当前工作目录的路径。
    • process.on(event, listener): 用于注册事件监听器。您可以使用 process.on 监听诸如 exit、uncaughtException 等事件,并在事件发生时执行相应的回调函数。
    • process.exit([code]): 用于退出当前的 Node.js 进程。您可以提供一个可选的退出码作为参数。
    • process.pid: 这个属性返回当前进程的 PID(进程 ID)。
  • Buffer :用于在 Node.js 应用中操作原始的二进制数据流
    • 创建  Buffer  实例:
      • Buffer.alloc(size[, fill[, encoding]]): 创建一个指定大小的新的 Buffer 实例,初始内容为零。fill 参数可用于填充缓冲区,encoding 参数指定填充的字符编码。
      • Buffer.from(array): 创建一个包含给定数组的 Buffer 实例。
      • Buffer.from(string[, encoding]): 创建一个包含给定字符串的 Buffer 实例。
    • 读取和写入数据:
      • buffer[index]: 通过索引读取或写入 Buffer 实例中的特定字节。
      • buffer.length: 获取 Buffer 实例的字节长度。
      • buffer.toString([encoding[, start[, end]]]): 将 Buffer 实例转换为字符串。
    • 转换数据:
      • buffer.toJSON(): 将 Buffer 实例转换为 JSON 对象。
      • buffer.slice([start[, end]]): 返回一个新的 Buffer 实例,其中包含原始 Buffer 实例的部分内容。
    • 其他方法:
      • Buffer.isBuffer(obj): 检查一个对象是否是 Buffer 实例。
      • Buffer.concat(list[, totalLength]): 将一组 Buffer 实例或字节数组连接起来形成一个新的 Buffer 实例。

SSR 服务端渲染

jsdom 是一个模拟浏览器环境的库,可以在 Node.js 中使用 DOM API 。

js
const fs = require('node:fs')
const { JSDOM } = require('jsdom')

const dom = new JSDOM(`<!DOCTYPE html><div id='app'></div>`)

const document = dom.window.document

fetch('https://api.thecatapi.com/v1/images/search?limit=10&page=1')
  .then((res) => res.json())
  .then((data) => {
    const app = document.getElementById('app')
    data.forEach((item) => {
      const img = document.createElement('img')
      img.src = item.url
      img.style.width = '200px'
      img.style.height = '200px'
      app.appendChild(img)
    })
    fs.writeFileSync('./index.html', dom.serialize())
  })

内置模块

stream 模块 (数据流处理)

用于处理数据流。

  • 可读流(Readable Streams):可读流用于从源读取数据。例如,读取文件、HTTP 请求、标准输入等都可以作为可读流。可读流可以通过事件驱动方式逐个或块状地读取数据
  • 可写流(Writable Streams):可写流用于将数据写入目标,例如写入文件、HTTP 响应、标准输出等。可写流通常通过调用 write() 方法来写入数据
  • 双工流(Duplex Streams):双工流既可以读取数据又可以写入数据。它是可读流和可写流的组合,例如 TCP 套接字
  • 转换流(Transform Streams):转换流是一种特殊的双工流,它允许你在读取和写入数据之间进行转换。通常用于数据的转换、压缩和解压缩等操作

TIP

可读流包括:

  • HTTP request / response
  • fs read streams
  • zlib streams
  • crypto streams
  • net TCP sockets
  • child process stdout / stderr
  • process.stdin

可写流包括:

  • HTTP request / response
  • fs write streams
  • zlib streams
  • crypto streams
  • net TCP sockets
  • child process stdin
  • process.stdout / process.stderr

双工流包括:

  • net TCP sockets
  • zlib streams
  • crypto streams

转换流包括:

  • zlib streams
  • crypto streams

使用

js
const stream = require('node:stream')

APIs

  • stream.pipeline(source[, ...transforms], destination, callback):用于连接多个可读流、可写流、双工流或转换流,并在完成后处理错误和关闭流
  • readableStream.pipe(destination[, options]): 将可读流连接到单个可写流,用于将数据从可读流传输到可写流。destination 是目标可写流,options 是可选的配置对象
  • readableStream.on(eventName, callback):注册一个事件监听器,eventName 可选值为:data(当可读流有新数据可用时触发)、end(当可读流的数据读取完毕时触发)、error(当可读流发生错误时触发)、close(当可读流被关闭时触发)、pause(当可读流暂停时触发)、readable(当可读流准备好读取数据时触发)、resume(当可读流恢复时触发)
  • readableStream.pause(): 暂停可读流的数据流动,停止触发 'data' 事件
  • readableStream.resume(): 恢复可读流的数据流动,继续触发 'data' 事件
  • readableStream.read([size]): 从可读流中读取指定大小的数据块,可选参数 size 指定要读取的字节数
  • readableStream.unshift(chunk): 将数据块推回可读流的缓冲区,以便在下一次读取时立即可用
  • readableStream.setEncoding(encoding):用于设置从可读流中读取数据时的字符编码
  • writableStream.write(chunk[, encoding][, callback]): 将数据块写入可写流。chunk 是要写入的数据,encoding 是可选的编码(通常用于字符串数据),callback 是写入完成后的回调函数
  • writableStream.on(eventName, callback): 注册一个事件监听器,eventName 可选值为:pipe(当一个可读流通过 pipe() 方法连接到可写流时触发)、unpipe(当一个可读流通过 unpipe() 方法从可写流断开连接时触发)、drain(当可写流内部的缓冲区已经被耗尽,并且可以继续写入数据时触发)、finish(当所有数据已经被成功写入可写流,并且可写流被关闭时触发)、error(当可写流发生错误时触发)、close(当可写流被关闭时触发)
  • writableStream.end([chunk][, encoding][, callback]): 结束可写流,可选地写入最后一块数据。这会触发 'finish' 事件
  • writableStream.setDefaultEncoding(encoding):用于设置从可写流中写入数据时默认的字符编码

zlib 模块(压缩和解压缩数据)

一个压缩和解压缩模块,支持 gzip、deflate、zlib 等压缩格式。

使用

js
const zlib = require('node:zlib')

APIs

分为异步 API 和同步 API,同步 API 在异步 API 后面追加 Sync 即可且不存在 callback。

  • zlib.brotliCompress(buffer[, options], callback):异步使用 Brotli 压缩算法对数据进行压缩并将结果传递给回调函数
  • zlib.brotliDecompress(buffer[, options], callback):异步使用 Brotli 解压算法对数据进行解压并将结果传递给回调函数
  • zlib.gzip(buffer[, options], callback):异步使用 Gzip 压缩算法压缩数据并将结果传递给回调函数
  • zlib.gunzip(buffer[, options], callback):异步使用 Gzip 解压缩算法解压缩数据并将结果传递给回调函数
  • zlib.deflate(buffer[, options], callback):异步压缩数据并将结果传递给回调函数
  • zlib.inflate(buffer[, options], callback):异步解压缩数据并将结果传递给回调函数
  • zlib.createBrotliCompress([options]): 创建一个 Brotli 压缩流
  • zlib.createBrotliDecompress([options]): 创建一个 Brotli 解压缩流
  • zlib.createDeflate([options]): 创建一个 Deflate 压缩流
  • zlib.createInflate([options]): 创建一个 Deflate 解压缩流
  • zlib.createGzip([options]): 创建一个 Gzip 压缩流
  • zlib.createGunzip([options]): 创建一个 Gzip 解压缩流

TIP

  • 客户端请求时

当客户端在请求中包含 'Accept-Encoding': 'gzip' 头部时,这表示客户端支持接收经过 Gzip 压缩的响应内容。服务器在接收到这个头部后,如果能够提供 Gzip 压缩的响应,就可以在响应中包含 'Content-Encoding': 'gzip' 来告知客户端可以接收压缩内容。

  • 服务器响应时

当服务器在响应中包含 'Content-Encoding': 'gzip' 头部时,这表示响应的内容已经被使用 Gzip 压缩算法进行了压缩。这通常用于减小传输的数据量,提高响应速度。客户端收到这个头部后,应该解压缩响应内容以获取原始数据。

fs 模块(文件系统)

与文件系统进行交互,包括读取文件、写入文件、创建目录、删除文件等文件操作。

使用

javascript
const fs = require('node:fs')

//promises风格
const fs = require('node:fs/promises')

APIs

分为异步 API 和同步 API,同步 API 在异步 API 后面追加 Sync 即可且不存在 callback。

  • fs.readFile(path[, options], callback):异步读取小文件内容
  • fs.writeFile(file, data[, options], callback):异步写入小文件内容
  • fs.createReadStream(path[, options]):异步读取大文件
javascript
const readableStream = fs.createReadStream('video.mp4')

readableStream.setEncoding('UTF8')

readableStream.on('data', (chunk) => {
  console.log('读取中...', chunk)
})

readableStream.on('end', () => {
  console.log('读取完毕')
})

readableStream.on('error', (err) => {
  console.log(err)
})

console.log('程序执行完毕')
  • fs.createWriteStream(path[, options]):异步写入大文件
javascript
const writableStream = fs.createWriteStream('video/video.mp4')

writableStream.write(writableStream, 'UTF8')
writableStream.end()

writableStream.on('finish', function () {
  console.log('写入完成。')
})

writableStream.on('error', function (err) {
  console.log(err)
})

console.log('程序执行完毕')

管道流:边读取边压缩边写入

javascript
const readableStream = fs.createReadStream('input.txt')
const writableStream = fs.createWriteStream('output.txt')
const gzip = zlib.createGzip()

readableStream.pipe(gzip).pipe(writableStream)

console.log('程序执行完毕')
  • fs.readdir(path, callback):异步读取指定目录下的文件和子目录
  • fs.mkdir(path[, options], callback):异步创建目录
  • fs.rmdir(path, callback):异步删除目录
  • fs.stat(path, callback):异步获取文件或目录的详细信息,如文件大小、创建时间等
  • fs.existsSync(path):同步检查文件或目录是否存在(异步 API 已弃用)
  • fs.rename(oldPath, newPath, callback):异步重命名文件或目录
  • fs.unlink(path, callback):异步删除文件
  • fs.copyFile(src, dest[, flags], callback):异步将文件从一个位置复制到另一个位置
  • fs.rename(oldPath, newPath, callback):异步文件重命名

path 模块(路径处理)

提供了一组方法,用于处理文件和目录的路径,确保在不同操作系统上的兼容性。

使用

javascript
const path = require('node:path')

APIs

  • path.join([...paths]):路径拼接
javascript
const pathStr = path.join('/a', '/b/c', '../', '/d', 'e')
console.log(pathStr) //output: \a\b\d\e

const pathStr2 = path.join(__dirname, './files/1.txt')
console.log(pathStr2) // output: 当前文件所在目录\files\1.txt
  • path.resolve([...paths]):获取绝对路径
javascript
path.resolve(__dirname, '..') //output:当前文件所在目录的上一级目录
path.resolve(__dirname, '..', '..') //output:当前文件所在目录的上两级目录
  • path.parse([...paths]):获取文件信息对象
javascript
path.parse('/home/user/dir/file.txt')
// output:
// {
//   root: '/',
//   dir: '/home/user/dir',
//   base: 'file.txt',
//   ext: '.txt',
//   name: 'file'
// }
  • path.basename(path[,ext]):获取路径中的文件名
javascript
let fileName = path.basename('/a/b/c/index.html')
//output:index.html

let baseNameWithoutExt = path.basename('/a/b/c/index.html', '.html')
//output: index
  • path.dirname(path):获取路径的目录
javascript
const dirName = path.dirname('/path/to/file.txt')
// output:'/path/to'
  • path.extname(path):获取路径中的文件扩展名
javascript
const fExt = path.extname('/a/b/c/index.html')
//output:.html
  • path.isAbsolute(path):判断是否为绝对路径
javascript
path.isAbsolute('/absolute/path') // output: true,这是绝对路径
path.isAbsolute('relative/path') // output: false,这是相对路径
  • path.normalize(path):规范路径
javascript
const nonNormalizedPath = 'C:\\my\\project\\..\\directory\\file.txt'
const normalizedPath = path.normalize(nonNormalizedPath)
// output: 'C:\my\directory\file.txt'
  • path.sep:一个表示当前平台路径分隔符的字符串(在 Windows 上是 \,在类 Unix 系统上是 /
  • path.delimiter:一个表示当前平台路径分隔符的字符串(在 Windows 上是 ;,在类 Unix 系统上是 :

url 模块(URL 处理)

用于解析和处理 URL,可以方便地从 URL 中提取信息。

APIs

  • new URL(input[, base]):若 input 是相对路径,则 bash 必填;若 input 是绝对路径,则 base 可选;若 input base 非字符串,则会先转换成字符串覆盖
js
let myURL = new URL('http://Example.com/', 'https://example.org/')
// http://example.com/

myURL = new URL('https://Example.com/', 'https://example.org/')
// https://example.com/

myURL = new URL('foo://Example.com/', 'https://example.org/')
// foo://Example.com/

myURL = new URL('http:Example.com/', 'https://example.org/')
// http://example.com/

myURL = new URL('https:Example.com/', 'https://example.org/')
// https://example.org/Example.com/

myURL = new URL('foo:Example.com/', 'https://example.org/')
// foo:Example.com/
相关属性
  • url.hash:获取 URL 的片段部分
js
const myURL = new URL('https://example.org/foo#bar')
console.log(myURL.hash)
// Prints #bar
  • url.host:获取 URL 的域名和端口
js
const myURL = new URL('https://example.org:81/foo')
console.log(myURL.host)
// Prints example.org:81
  • url.hostname:获取 URL 的域名
js
const myURL = new URL('https://example.org:81/foo')
console.log(myURL.hostname)
// Prints example.org
  • url.href:获取 URL 的完整路径
js
const myURL = new URL('https://example.org/foo')
console.log(myURL.href)
// Prints https://example.org/foo
  • url.origin:获取 URL 的协议和域名
js
const myURL = new URL('https://example.org/foo/bar?baz')
console.log(myURL.origin)
// Prints https://example.org
  • url.pathname:获取 URL 的目录路径
js
const myURL = new URL('https://example.org/abc/xyz?123')
console.log(myURL.pathname)
// Prints /abc/xyz
  • url.port:获取 URL 的端口
js
const myURL = new URL('https://example.org:8888')
console.log(myURL.port)
// Prints 8888
  • url.protocol:获取 URL 的协议
js
const myURL = new URL('https://example.org')
console.log(myURL.protocol)
// Prints https:
  • url.search:获取 URL 的 query 参数
js
const myURL = new URL('https://example.org/abc?foo=123')
console.log(myURL.search)
// Prints ?foo=123
  • url.searchParams:获取 URL 的 query 参数 URLSearchParams 的对象,并忽略分隔符 ?
js
const myURL = new URL('https://example.org/abc?foo=123')
console.log(myURL.searchParams.toString()) // Prints foo=123
console.log(myURL.searchParams.get('foo')) // Prints 123

querystring 模块(查询字符串解析)

用于解析和格式化 URL 查询字符串。

使用

js
const querystring = require('node:querystring')

APIs

  • querystring.parse(str[, sep[, eq[, options]]]):将 URL 查询字符串解析为对象。
javascript
const queryString = 'foo=123&bar=abc&baz=true'
const parsedObject = querystring.parse(queryString)

console.log(parsedObject)
/*
输出结果:
{
  foo: '123',
  bar: 'abc',
  baz: 'true'
}
*/
  • querystring.stringify(obj[, sep[, eq[, options]]]):将一个对象转换成查询字符串。
javascript
const objectToSerialize = {
  foo: '123',
  bar: 'abc',
  baz: true
}

const serializedString = querystring.stringify(objectToSerialize)

console.log(serializedString) // 输出: 'foo=123&bar=abc&baz=true'

http/https 模块(服务器和客户端)

创建 HTTP 服务器和 HTTP 客户端,用于构建 Web 应用程序和处理 HTTP 请求。

使用

js
const http = require('node:http')

APIs

  • http.createServer([options][, requestListener]):创建 HTTP 服务器并处理 HTTP 请求
javascript
const server = http.createServer((req, res) => {
  if (req.url === '/') {
    res.writeHead(200, {
      'Content-Type': 'text/plain;charset=utf-8'
    })
    res.end('Hello, World!')
  } else if (req.url === '/about') {
    res.writeHead(200, {
      'Content-Type': 'text/plain;charset=utf-8'
    })
    res.end('About Page')
  } else {
    res.writeHead(404)
    res.end('Not Found')
  }
})

server.listen(3000, () => {
  console.log('Server is running on http://localhost:3000')
})

TIP

  • res.setHeader(name, value):可以多次调用 setHeader 来设置多个响应头部。如果多次设置相同名称的头部,后面的设置会覆盖之前的设置
  • res.writeHead(statusCode[, statusMessage][, headers]):一次性设置响应状态码、状态消息和响应头部信息。如果之后再使用 response.setHeader 来设置相同名称的头部,可能会导致重复的头部出现
JSONP
  1. 创建一个 Node.js 服务器:
js
const http = require('http')
const querystring = require('querystring')

const server = http.createServer((req, res) => {
  // 解析请求的 URL
  const parsedUrl = new URL(req.url)
  const query = querystring.parse(parsedUrl.searchParams.toString())

  // 处理 JSONP 请求
  if (query.callback && query.data) {
    // 设置响应头
    res.setHeader('Content-Type', 'application/javascript; charset=utf-8')

    // 构建 JSONP 响应
    const response = `${query.callback}(${JSON.stringify(query.data)})`

    // 发送响应
    res.end(response)
  } else {
    // 处理其他请求
    res.writeHead(404)
    res.end('Not Found')
  }
})

server.listen(3000, () => {
  console.log('Server is listening on port 3000')
})
  1. 在客户端,你可以使用动态创建 <script> 标签来请求 JSONP 数据:
html
<!DOCTYPE html>
<html>
  <head>
    <title>JSONP Example</title>
  </head>
  <body>
    <script>
      function handleResponse(data) {
        // 处理从服务器返回的数据
        console.log('Received data:', data)
      }

      // 创建一个 script 元素并设置 src
      const script = document.createElement('script')
      script.src =
        'http://localhost:3000/jsonp?callback=handleResponse&data={"name":"John","age":30}'

      // 将 script 元素添加到文档中
      document.body.appendChild(script)
    </script>
  </body>
</html>
CORS
javascript
const server = http.createServer((req, res) => {
  if (req.url === '/data') {
    res.writeHead(200, {
      'Content-Type': 'application/json; charset=utf-8',
      'Access-Control-Allow-Origin': '*'
    })
    res.end(JSON.stringify({ message: 'Hello, CORS is enabled!' }))
  } else {
    res.writeHead(404)
    res.end('Not Found')
  }
})

server.listen(3000, () => {
  console.log('Server is listening on port 3000')
})
  • http.get(url[, options][, callback]):用于(向第三方服务器)发送仅 GET 请求
js
// 发起 GET 请求
const req = http.get('http://jsonplaceholder.typicode.com/posts', (res) => {
  let data = ''

  // 监听响应数据事件
  res.on('data', (chunk) => {
    data += chunk
  })

  // 监听响应结束事件
  res.on('end', () => {
    // 在这里处理响应数据
    console.log('响应数据:', data)
  })
})

// 监听请求错误事件
req.on('error', (error) => {
  console.error('请求错误:', error)
})

// 结束请求
req.end()
  • http.request(options[, callback]):用于(向第三方服务器)发送任何类型的 HTTP 请求(GET、POST、PUT 等)
js
// 请求配置选项
const options = {
  hostname: 'jsonplaceholder.typicode.com',
  port: 80,
  path: '/posts',
  method: 'POST',
  headers: {
    'Content-Type': 'application/json; charset=utf-8'
  }
}

// 创建 HTTP 请求
const req = http.request(options, (res) => {
  let data = ''

  // 监听响应数据事件
  res.on('data', (chunk) => {
    data += chunk
  })

  // 监听响应结束事件
  res.on('end', () => {
    // 在这里处理响应数据
    console.log('响应数据:', data)
  })
})

// 发送请求体数据
req.write(
  JSON.stringify({
    title: 'foo',
    body: 'bar',
    userId: 1
  })
)

// 监听请求错误事件
req.on('error', (error) => {
  console.error('请求错误:', error)
})

// 结束请求
req.end()

event 模块(事件处理)

提供了一个核心类,即 EventEmitter,用于处理事件和事件监听器。EventEmitter 类提供了一些方法,允许创建、触发、监听和移除事件。

使用

js
const EventEmitter = require('events').EventEmitter
const myEmitter = new EventEmitter()
// 或
const EventEmitter = require('events')
class MyEmitter extends EventEmitter {}
const myEmitter = new MyEmitter()

APIs

  • emitter.on(eventName, listener):注册事件处理程序。当事件 event 被触发时,与之关联的 listener 函数将被调用

  • emitter.once(eventName, listener):注册一次性事件处理程序。这个处理程序只会在第一次触发事件时被调用,之后将被自动删除

  • emitter.emit(eventName[, ...args]):触发事件。当事件 event 被触发时,与之关联的事件处理程序将被调用,可选参数 ...args 将被传递给事件处理程序

  • emitter.off(eventName, listener):用于取消一个事件监听器的注册。

  • emitter.setMaxListeners(n):设置事件发射器(或事件管理器)的最大监听器数量,默认为 10

  • emitter.getMaxListeners():用于获取事件发射器(或事件管理器)的最大监听器数量

js
// First listener
myEmitter.on('event', function firstListener() {
  console.log('Helloooo! first listener')
})
// Second listener
myEmitter.on('event', function secondListener(arg1, arg2) {
  console.log(`event with parameters ${arg1}, ${arg2} in second listener`)
})
// Third listener
myEmitter.on('event', function thirdListener(...args) {
  const parameters = args.join(', ')
  console.log(`event with parameters ${parameters} in third listener`)
})

console.log(myEmitter.listeners('event'))

myEmitter.emit('event', 1, 2, 3, 4, 5)

// Prints:
// [
//   [Function: firstListener],
//   [Function: secondListener],
//   [Function: thirdListener]
// ]
// Helloooo! first listener
// event with parameters 1, 2 in second listener
// event with parameters 1, 2, 3, 4, 5 in third listener

crypto 模块(加密)

提供了加密和解密的功能,包括哈希算法、对称加密、非对称加密、数字签名等。

使用

js
cosnt cryto = require('node:cryto');

APIs

  • crypto.createHash(algorithm[, options]):创建一个哈希对象,用于计算哈希值
javascript
/** MD5 哈希算法 */
const hash = crypto.createHash('md5')

// 更新哈希对象的内容
hash.update('Hello, Node.js!')

// 计算哈希值,并以十六进制编码的形式输出
const hashValue = hash.digest('hex')

console.log('MD5 哈希值:', hashValue)
  • crypto.createHmac(algorithm, key[, options]):创建一个 HMAC 对象,用于验证消息的完整性和验证身份
javascript
/** SHA-256 哈希算法 */
const hmac = crypto.createHmac('sha256', 'mySecretKey')

// 更新 HMAC 对象的内容
hmac.update('Hello, HMAC!')

// 生成 HMAC 签名,并以base64编码的形式输出
const signature = hmac.digest('base64')

console.log('生成的 HMAC 签名:', signature)
  • crypto.createCipheriv(algorithm, key, iv[, options]):创建一个对称加密对象,用于加密数据
js
/** aes-256-cbc 加密算法 */
const cipher = crypto.createCipheriv(
  'aes-256-cbc',
  'abcdef1234567890',
  '1234567890abcdef'
)

// 更新加密器的内容
let encryptedData = cipher.update('Hello, Node.js!', 'utf8', 'hex')

// 处理最后一个数据块并返回结果
encryptedData += cipher.final('hex')

console.log('加密后的数据:', encryptedData)
  • crypto.createDecipheriv(algorithm, key, iv[, options]):创建一个对称解密对象,用于解密数据
javascript
/** aes-256-cbc 解密算法 */
const decipher = crypto.createDecipheriv(
  'aes-256-cbc',
  'abcdef1234567890',
  '1234567890abcdef'
)

// 更新解密器的内容
let decryptedData = decipher.update(
  '8f3b837f5e9f558545b9d2ac3e582e3d',
  'hex',
  'utf8'
)

// 处理最后一个数据块并返回结果
decryptedData += decipher.final('utf8')

console.log('解密后的数据:', decryptedData)
  • crypto.randomBytes(size[, callback]):生成指定大小的随机字节
js
const buf = crypto.randomBytes(256)

console.log(`${buf.length} bytes of random data: ${buf.toString('hex')}`)

OS 模块(操作系统信息)

提供了访问操作系统相关信息的方法,如获取操作系统类型、内存使用情况等。

使用

js
const os = require('node:os')

APIs

  • os.platform():返回当前操作系统的平台名称,例如 "darwin" 表示 macOS,"win32" 表示 Windows
  • os.arch():返回处理器的架构,例如 "x64" 表示 64 位处理器
  • os.type():返回操作系统的名称,例如 "Linux" 或 "Windows_NT"
  • os.release():返回操作系统的版本号
  • os.cpus():返回一个包含有关 CPU 内核信息的数组,每个元素代表一个 CPU 内核
  • os.totalmem():返回系统的总内存量(以字节为单位)
  • os.freemem():返回系统的可用内存量(以字节为单位)
  • os.hostname():返回计算机的主机名
  • os.userInfo([options]):返回关于当前用户的信息,包括用户名、用户 ID、组 ID、shell 和家目录等
  • os.networkInterfaces():返回一个对象,其中包含计算机的网络接口信息,包括 IP 地址、MAC 地址等

Process 模块(进程处理)

提供了对当前 Node.js 进程的控制和信息访问。

使用

js
const process = require('node:process')

APIs

  • process.argv:一个数组,包含 Node.js 进程的命令行参数。第一个元素是 Node.js 可执行文件的路径,第二个元素是当前执行的 JavaScript 文件的路径,后续元素是命令行参数
  • process.env:一个包含操作系统环境变量的对象。您可以使用它来读取或设置环境变量的值
  • process.stdin:标准输入流,用于从控制台接收用户输入
  • process.stdout:标准输出流,用于向控制台输出数据
  • process.stderr:标准错误流,用于向控制台输出错误信息
  • process.on(event, callback):用于监听各种事件,例如 exit(进程即将退出时触发)、uncaughtException(未捕获的异常),以及其他自定义事件
  • process.exit([code]):用于终止 Node.js 进程,可选地提供退出码(默认为 0 表示成功)
  • process.memoryUsage():返回一个包含有关 Node.js 进程内存使用情况的对象,包括堆内存、常驻内存等信息
  • process.cwd():返回当前工作目录的路径
  • process.pid:返回当前进程的 PID(进程标识符)
  • process.chdir(directory):用于更改当前工作目录
  • process.kill(pid[, signal]):用于向指定的进程发送信号。可以用于终止其他进程
  • process.cpuUsage([previousValue]):返回一个包含有关 CPU 使用情况的对象,包括用户和系统 CPU 时间
  • process.uptime():返回 Node.js 进程的运行时间,以秒为单位
  • process.hrtime([time]):用于测量时间间隔,可以用于性能分析和时间计算
  • process.nextTick(callback):将回调函数安排在当前执行栈完成后立即执行,通常用于异步操作中的回调函数

child_process 模块 (子进程)

创建和控制子进程,与外部命令进行交互。

使用

js
const { exec, spawn, execFile, fork } = require('node:child_process')

APIs

  • child_process.spawn(command[, args][, options]):以异步的方式启动一个外部命令或脚本。可以指定命令、参数和选项,然后返回一个表示子进程的 ChildProcess 对象
js
const ls = spawn('ls', ['-l', '/usr'])

ls.stdout.on('data', (data) => {
  console.log(`stdout: ${data}`)
})

ls.stderr.on('data', (data) => {
  console.error(`stderr: ${data}`)
})

ls.on('close', (code) => {
  console.log(`Child process exited with code ${code}`)
})
  • child_process.exec(command[, options][, callback]):以异步的方式执行外部命令,并获取其标准输出和标准错误输出。可选的回调函数将在命令执行完成后被调用,传递执行结果
js
exec('ls -l /usr', (error, stdout, stderr) => {
  if (error) {
    console.error(`Error: ${error}`)
    return
  }
  console.log(`stdout: ${stdout}`)
  console.error(`stderr: ${stderr}`)
})
  • child_process.execFile(file[, args][, options][, callback]):与 exec 类似,但是直接执行一个文件,而不是通过 shell
js
execFile('node', ['--version'], (error, stdout, stderr) => {
  if (error) {
    console.error(`执行出错: ${error}`)
    return
  }
  console.log(`stdout: ${stdout}`)
  console.error(`stderr: ${stderr}`)
})
  • child_process.fork(modulePath[, args][, options]):创建一个新的 Node.js 子进程,运行指定的模块文件,可选地传递参数和选项
js
const child = fork('worker.js')

child.on('message', (message) => {
  console.log(`父进程收到消息:${message}`)
})

child.send({ hello: 'world' })
  • ChildProcess.stdin:标准输入流,允许向子进程发送数据。
  • ChildProcess.stdout:标准输出流,用于从子进程接收数据。
  • ChildProcess.stderr:标准错误输出流,用于从子进程接收错误信息
js
const child = spawn('node')

child.stdin.write('console.log("Hello, child process!");')
child.stdin.end()

child.stdout.on('data', (data) => {
  console.log(`Child process stdout: ${data}`)
})
  • ChildProcess.kill([signal]):用于向子进程发送信号以终止它
js
const child = spawn('node', ['script.js'])

// 终止子进程
setTimeout(() => {
  child.kill('SIGTERM')
}, 5000)

net 模块 (网络通信)

用于创建 TCP 和 Unix 域套接字服务器和客户端,用于构建网络应用程序。

使用

js
const net = require('node:net')

APIs

  • net.createServer([options][, connectionListener]):用于创建 TCP 服务器。可以使用此函数来监听指定端口,并在客户端连接时执行回调函数
js
const server = net.createServer((socket) => {
  console.log('Client connected')

  socket.on('data', (data) => {
    console.log(`Received data: ${data}`)
    socket.write('Hello from server!')
  })

  socket.on('end', () => {
    console.log('Client disconnected')
  })
})

const PORT = 8080
server.listen(PORT, () => {
  console.log(`Server listening on port ${PORT}`)
})
  • net.createConnection(options[, connectionListener]):用于创建 TCP 客户端连接到远程服务器。可以使用此函数来连接到指定主机和端口,并在连接建立时执行回调函数
js
const client = net.createConnection({ port: 8080 }, () => {
  console.log('Connected to server')
  client.write('Hello from client!')
})

client.on('data', (data) => {
  console.log(`Received data: ${data}`)
  client.end()
})

client.on('end', () => {
  console.log('Disconnected from server')
})

dns 模块 (DNS 解析)

用于进行 DNS 查询,包括域名解析和逆向解析。

使用

js
const dns = require('node:dns')

APIs

  • dns.lookup(hostname[, options], callback):将主机名(域名)解析为第一个找到的 IP 地址,并将结果传递给回调函数。可选的 options 参数用于指定解析的 IP 版本(IPv4 或 IPv6)
js
dns.lookup('www.example.com', (err, address, family) => {
  if (err) throw err
  console.log('IP address:', address)
})
  • dns.resolve(hostname[, rrtype], callback):根据指定的资源记录类型(例如 'A'、'MX'、'CNAME' 等)解析主机名。结果将是一个数组,包含所有匹配的记录
js
dns.resolve('www.example.com', 'A', (err, addresses) => {
  if (err) throw err
  console.log('IP addresses:', addresses)
})
  • dns.reverse(ip, callback):将 IP 地址解析为与之关联的主机名(域名)。结果将是一个数组,包含所有匹配的主机名
js
dns.reverse('8.8.8.8', (err, hostnames) => {
  if (err) throw err
  console.log('Hostnames:', hostnames)
})
  • dns.setServers(servers):允许您设置自定义的 DNS 解析服务器。默认情况下,Node.js 使用操作系统配置的 DNS 服务器,但您可以使用此函数指定要使用的 DNS 服务器的 IP 地址数组
js
dns.setServers(['8.8.8.8', '8.8.4.4']) // 设置 Google 的 DNS 服务器

dns.lookup('www.example.com', (err, address) => {
  if (err) throw err
  console.log('Custom DNS IP address:', address)
})

readline 模块 (逐行读取)

用于逐行读取用户输入,特别适用于构建命令行界面。

使用

js
const readline = require('node:readline')
// 或
const readline = require('node:readline/promises')

APIs

  • readline.createInterface(options):用于创建一个 Readline 接口对象,该对象可以用于逐行读取数据。可以通过提供选项来配置接口,例如指定输入和输出流
js
const rl = readline.createInterface({
  input: process.stdin, // 使用标准输入流作为输入
  output: process.stdout // 使用标准输出流作为输出
})

rl.question('What is your name? ', (answer) => {
  console.log(`Hello, ${answer}!`)
  rl.close() // 关闭 Readline 接口
})

rl.write('Delete this!')
rl.write(null, { ctrl: true, name: 'u' }) // 按住 Ctrl+U 删除该行

rl.on('line', (input) => {
  console.log(`Received: ${input}`)
})

util 模块 (实用工具)

包含一些实用工具函数,用于处理对象、继承和其他常见任务。

使用

js
const util = require('node:util')

APIs

  • util.inherits(constructor, superConstructor):用于实现对象间的继承关系。它会将子构造函数的原型对象链接到父构造函数的原型对象上,从而实现原型链继承
  • util.inspect(object, [options]):将对象转换为字符串表示,通常用于调试和日志输出
  • util.promisify(original):将回调风格的异步函数转换为返回 Promise 的版本,便于使用 async/await
  • util.isArray(object):检查对象是否是数组
  • util.isDate(object):检查对象是否是日期对象
  • util.isError(object):检查对象是否是错误对象
  • util.format(format[, ...args]):格式化字符串,类似于 console.log,但返回格式化后的字符串而不是输出到控制台
  • util.deprecate(fn, message):标记函数已弃用,当函数被调用时会显示警告消息

读书、摄影、画画、弹琴、编程