安装和配置 安装
下载安装包 , Windows的话, 下载安装包, 直接安装就可以。
Linux安装1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 mkdir /opt/nodejs tar -xvf node-v20.12.0-linux-x64.tar.xz mkdir /usr/local/nodemv /opt/nodejs/node-v20.12.0-linux-x64 /usr/local/nodesudo vi /etc/profile export M2_HOME=/usr/local/maven/apache-maven-3.9.6export PATH=$PATH :$JAVA_HOME /bin:$M2_HOME /binsource /etc/profilenode -v
配置 在Windows中因为Windows PowerShell默认限制了执行脚本的权限, 所以需要修改权限。 打开Windows PowerShell( 需要以管理员身份运行) 。 你可以通过在开始菜单搜索“ PowerShell” , 然后右键点击并选择“ 以管理员身份运行” 。
对本次会话有效
Set-ExecutionPolicy Bypass -Scope Process
对当前用户生效
Set-ExecutionPolicy RemoteSigned -Scope CurrentUser
对所有用户给生效
Set-ExecutionPolicy RemoteSigned -Scope LocalMachine
常用命令 查看Node版本
修改镜像源 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 npm config get registry npm config set registry=https://registry.npmmirror.com/ npm install -g nrm nrm --version nrm ls nrm use taobao nrm current
查看包的版本 1 npm view hexo-cli versions
安装模块 1 2 3 4 5 6 7 8 9 10 11 npm install 包名 npm install 包名@版本号 npm install -g 包名 npm install 包名 -D
初始化项目 1 2 3 npm init <名称> cd <名称>npm install
卸载模块
更新模块
运行脚本
发布模块
模块化 模块化是其核心概念之一, 它允许你将代码分割成独立的模块, 以便于维护和组织。 Node.js 使用的是 CommonJS 模块系统, 这种模式下, 每个模块都运行在一个单独的模块作用域内, 也就是说, 在模块里定义的变量、 函数和对象默认都是私有的, 除非明确地将其导出。
创建模块 ⭐⭐ 在Node.js中, 使用module.exports
或exports
来导出模块接口给其他模块使用。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 function add (a, b ) { return a + b; } function subtract (a, b ) { return a - b; } module .exports = { add : add, subtract : subtract };
导入模块 使用require()
导入自定义模块时, 必须指定以./
或../
开头的路径标识符。 如果没有指定路径标识符, 则 node 会把它当作内置模块或第三方模块进行加载。
使用require()
导入自定义模块时, 如果省略了文件的扩展名, 则 Node.js 会按顺序分别尝试加载以下的文件
按照确切的文件名进行加载
补全 js 扩展名进行加载
补全 json 扩展名进行加载
补全 .node 扩展名进行加载
加载失败, 终端报错
⭐⭐ 在Node.js中, 使用require()
函数来导入模块。 1 2 3 4 5 6 7 8 const math = require ('./math' );console .log (math.add (5 , 3 )); console .log (math.subtract (5 , 3 ));
ES6 模块支持 从 Node.js v12 开始, 实验性地支持了ES6模块语法。 你可以通过.mjs
扩展名或者在package.json
中设置"type": "module"
来启用对ES模块的支持。
1 2 3 4 5 6 7 8 9 10 11 export function add (a, b ) { return a + b; } import { add } from './math.mjs' ;console .log (add (5 , 3 ));
内置模块 Node.js 提供了一系列内置模块, 这些模块无需安装即可直接通过require()
函数使用。 内置模块覆盖了从文件系统访问、 网络通信到数据流处理等多个方面。
fs 模块 fs 模块提供了一个用于与文件系统交互的 API。 这个模块是基于标准 POSIX 函数构建的, 因此在命名和功能上与它们非常相似。 无论你是要读取文件、 写入数据到文件还是操作目录, fs 模块都能满足你的需求。
读取文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const fs = require ('fs' );fs.readFile ('./example.txt' , 'utf8' , (err, data ) => { if (err) throw err; console .log (data); }); try { const data = fs.readFileSync ('./example.txt' , 'utf8' ); console .log (data); } catch (err) { console .error (err); }
写入文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const fs = require ('fs' );fs.writeFile ('./output.txt' , 'Hello, World!' , (err ) => { if (err) throw err; console .log ('File saved!' ); }); try { fs.writeFileSync ('./output.txt' , 'Hello, World!' ); console .log ('File saved!' ); } catch (err) { console .error (err); }
文件状态 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const fs = require ('fs' );fs.stat ('./example.txt' , (err, stats ) => { if (err) throw err; console .log (`Is file: ${stats.isFile()} ` ); }); fs.lstat ('./symlink' , (err, stats ) => { if (err) throw err; console .log (`Is symbolic link: ${stats.isSymbolicLink()} ` ); });
创建目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const fs = require ('fs' );fs.mkdir ('./newDir' , { recursive : true }, (err ) => { if (err) throw err; console .log ('Directory created' ); }); try { fs.mkdirSync ('./newDir' , { recursive : true }); console .log ('Directory created' ); } catch (err) { console .error (err); }
读取目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const fs = require ('fs' );fs.readdir ('./someDir' , (err, files ) => { if (err) throw err; console .log (files); }); try { const files = fs.readdirSync ('./someDir' ); console .log (files); } catch (err) { console .error (err); }
删除文件/目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const fs = require ('fs' );fs.unlink ('./toBeDeleted.txt' , (err ) => { if (err) throw err; console .log ('File deleted' ); }); fs.rmdir ('./toBeDeletedDir' , (err ) => { if (err) throw err; console .log ('Directory deleted' ); });
重命名文件/目录 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const fs = require ('fs' );fs.rename ('./oldName' , './newName' , (err ) => { if (err) throw err; console .log ('Renamed successfully' ); });
流式处理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const fs = require ('fs' );const readStream = fs.createReadStream ('./largeFile.txt' );readStream.on ('data' , (chunk ) => { console .log (`Received ${chunk.length} bytes of data.` ); }); readStream.on ('end' , () => { console .log ('Finished reading the file.' ); }); const writeStream = fs.createWriteStream ('./output.txt' );writeStream.write ('Hello, world!\n' ); writeStream.end ();
path 模块 path 模块提供了用于处理和转换文件路径的实用工具。 无论你是在 Windows、 Linux 还是 macOS 上运行 Node.js, path 模块都能确保你的代码在不同操作系统之间保持一致的行为。
文件路径 1 2 3 4 5 console .log (__dirname);const path = require ('path' );console .log (path.dirname ('/foo/bar/baz/asdf/quux.html' ));
文件扩展名 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const path = require ('path' );console .log (path.basename ('/foo/bar/baz/asdf/quux.html' )); console .log (path.basename ('/foo/bar/baz/asdf/quux.html' , '.html' )); const path = require ('path' );console .log (path.extname ('index.html' )); console .log (path.extname ('index.' )); console .log (path.extname ('index' ));
拼接路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const path = require ('path' );console .log (path.join ('/foo' , 'bar' , 'baz/asdf' , 'quux' , '..' )); const path = require ('path' );console .log (path.normalize ('/foo/bar//baz/asdf/quux/..' ));
格式化路径 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const path = require ('path' );console .log (path.format ({ dir : '/home/user/dir' , base : 'file.txt' })); const path = require ('path' );console .log (path.parse ('/home/user/dir/file.txt' ));
相对路径 1 2 3 4 5 6 7 8 9 const path = require ('path' );console .log (path.relative ('/data/orandea/test/aaa' , '/data/orandea/impl/bbb' ));
绝对路径 1 2 3 4 5 6 7 8 const path = require ('path' );console .log (path.resolve ('/foo/bar' , './baz' )); console .log (path.resolve ('/foo/bar' , '/tmp/file/' ));
路径分隔符 1 2 3 4 5 6 const path = require ('path' );console .log (path.sep );
http 模块 http 模块提供了一个用于创建 HTTP 服务器和客户端的接口, 使得你可以轻松地在 Node.js 应用中处理 HTTP 请求和响应。
创建HTTP服务器 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const http = require ('http' );const server = http.createServer ((req, res ) => { console .log ('Request received' ); res.writeHead (200 , { 'Content-Type' : 'text/plain' }); res.end ('Hello, World!\n' ); }); server.listen (3000 , () => { console .log ('Server running at http://localhost:3000/' ); });
发送HTTP请求 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 const http = require ('http' );const options = { hostname : 'www.example.com' , port : 80 , path : '/' , method : 'GET' }; const req = http.request (options, (res ) => { let data = '' ; res.on ('data' , (chunk ) => { data += chunk; }); res.on ('end' , () => { console .log (data); }); }); req.on ('error' , (e ) => { console .error (`Problem with request: ${e.message} ` ); }); req.end ();
发送GET请求 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const http = require ('http' );http.get ('http://www.example.com/' , (res ) => { let data = '' ; res.on ('data' , (chunk ) => { data += chunk; }); res.on ('end' , () => { console .log (data); }); }).on ('error' , (e ) => { console .error (`Got error: ${e.message} ` ); });
模块常量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const http = require ('http' );console .log (http.METHODS );console .log (http.STATUS_CODES [404 ]);
os 模块 获取操作系统信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 const os = require ('os' );console .log (os.arch ()); console .log (os.platform ()); console .log (os.type ()); console .log (os.release ()); console .log (os.loadavg ()); console .log (os.tmpdir ()); console .log (`${os.uptime()} seconds` ); console .log (os.hostname ()); console .log (os.userInfo ());
获取CPU信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const os = require ('os' );console .log (`${os.totalmem() / (1024 * 1024 * 1024 )} GB` ); console .log (`${os.freemem() / (1024 * 1024 * 1024 )} GB` ); console .log (os.cpus ());
获取网络接口信息 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const os = require ('os' );console .log (os.networkInterfaces ());
url 模块 url 模块提供了用于解析和处理 URL 的实用工具。 这个模块非常有用, 尤其是在你需要处理复杂的 URL 字符串、 构建新的 URL 或者对现有 URL 进行操作时。
解析 URL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const { URL } = require ('url' );const urlString = 'https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash' ;const parsedUrl = new URL (urlString);console .log (parsedUrl);
序列化 URL 对象 1 2 3 4 5 6 7 8 const { URL } = require ('url' );const url = new URL ('https://user:pass@sub.host.com:8080/p/a/t/h?query=string#hash' );console .log (url.href );
处理查询参数 1 2 3 4 5 6 7 8 9 10 const { URLSearchParams } = require ('url' );const params = new URLSearchParams ('foo=bar&abc=xyz' );console .log (params.get ('foo' )); params.append ('foo' , 'baz' ); console .log (params.toString ());
相对 URL 转换 1 2 3 4 5 6 7 8 9 10 11 const url = require ('url' );const baseUrl = 'http://example.com/path/' ;const relativeUrl = './other/path' ;const resolvedUrl = url.resolve (baseUrl, relativeUrl);console .log (resolvedUrl);
zlib 模块 zlib 模块提供了压缩和解压缩功能, 支持 Gzip 和 Deflate 压缩算法。 适用于多种应用场景, 如网络传输中的数据压缩、 日志文件的压缩存储等。
创建压缩流 ⭐⭐ Gzip 压缩 1 2 3 4 5 6 7 8 9 10 11 12 13 14 const fs = require ('fs' );const zlib = require ('zlib' );const gzip = zlib.createGzip ();const inFile = fs.createReadStream ('input.txt' );const outFile = fs.createWriteStream ('input.txt.gz' );inFile.pipe (gzip).pipe (outFile); console .log ('文件已成功压缩为 Gzip 格式' );
⭐⭐ Deflate 压缩 1 2 3 4 5 6 7 8 9 10 11 12 13 14 const fs = require ('fs' );const zlib = require ('zlib' );const deflate = zlib.createDeflate ();const inFile = fs.createReadStream ('input.txt' );const outFile = fs.createWriteStream ('input.txt.deflate' );inFile.pipe (deflate).pipe (outFile); console .log ('文件已成功压缩为 Deflate 格式' );
解压缩流 ⭐⭐ Gzip 解压缩 1 2 3 4 5 6 7 8 9 10 11 12 const fs = require ('fs' );const zlib = require ('zlib' );const gunzip = zlib.createGunzip ();const inFile = fs.createReadStream ('input.txt.gz' );const outFile = fs.createWriteStream ('output.txt' );inFile.pipe (gunzip).pipe (outFile); console .log ('文件已成功解压缩' );
⭐⭐ Deflate 解压缩 1 2 3 4 5 6 7 8 9 10 11 12 const fs = require ('fs' );const zlib = require ('zlib' );const inflate = zlib.createInflate ();const inFile = fs.createReadStream ('input.txt.deflate' );const outFile = fs.createWriteStream ('output.txt' );inFile.pipe (inflate).pipe (outFile); console .log ('文件已成功解压缩' );
同步压缩与解压缩 除了流处理, zlib 模块还提供了同步方法来进行一次性压缩和解压缩操作。
⭐⭐ 同步压缩数据 1 2 3 4 5 6 const zlib = require ('zlib' );const data = 'This is a sample string to be compressed' ;const compressedData = zlib.deflateSync (Buffer .from (data));console .log ('压缩后的数据:' , compressedData.toString ('base64' ));
⭐⭐ 同步解压缩数据 1 2 3 4 5 6 const zlib = require ('zlib' );const compressedData = Buffer .from ('压缩后的数据' , 'base64' );const decompressedData = zlib.inflateSync (compressedData);console .log ('解压缩后的数据:' , decompressedData.toString ());
高级选项 zlib 提供了一些高级选项来调整压缩行为, 例如设置压缩级别、 内存窗口大小等。
⭐⭐ 设置压缩级别 1 2 3 4 5 6 7 8 9 const zlib = require ('zlib' );const data = 'This is a sample string to be compressed' ;const compressedData = zlib.deflateSync (Buffer .from (data), { level : 9 });console .log ('压缩后的数据:' , compressedData.toString ('base64' ));
⭐⭐ 设置内存窗口大小 1 2 3 4 5 6 7 8 9 const zlib = require ('zlib' );const data = 'This is a sample string to be compressed' ;const compressedData = zlib.deflateSync (Buffer .from (data), { windowBits : 16 + 15 });console .log ('压缩后的数据:' , compressedData.toString ('base64' ));
crypto 模块 crypto 模块提供了加密功能, 包括哈希、 HMAC、 加密、 解密、 签名和验证等。 这个模块非常强大且灵活, 适用于需要处理敏感数据的应用场景, 如密码存储、 数据加密传输等。
哈希 哈希函数将任意长度的数据映射为固定长度的输出, 常用于数据完整性校验和密码存储。
1 2 3 4 5 6 7 8 9 10 11 const crypto = require ('crypto' );const hash = crypto.createHash ('sha256' );hash.update ('Some data to hash' ); console .log (hash.digest ('hex' ));
HMAC HMAC 是一种基于哈希的消息认证码, 通常用于验证消息的完整性和真实性。
1 2 3 4 5 6 7 8 9 10 const crypto = require ('crypto' );const hmac = crypto.createHmac ('sha256' , 'secret-key' );hmac.update ('Some data to hash' ); console .log (hmac.digest ('hex' ));
加密/解密 crypto 模块支持多种对称加密算法( 如 AES) , 可以用来加密和解密数据。
⭐⭐ 对称加密 1 2 3 4 5 6 7 8 9 10 11 12 13 const crypto = require ('crypto' );const key = crypto.randomBytes (32 ); const iv = crypto.randomBytes (16 ); const cipher = crypto.createCipheriv ('aes-256-cbc' , key, iv);let encrypted = cipher.update ('Some secret message' , 'utf8' , 'hex' );encrypted += cipher.final ('hex' ); console .log (`加密后的数据: ${encrypted} ` );
⭐⭐ 对称解密 1 2 3 4 5 6 7 8 9 const crypto = require ('crypto' );const decipher = crypto.createDecipheriv ('aes-256-cbc' , key, iv);let decrypted = decipher.update (encrypted, 'hex' , 'utf8' );decrypted += decipher.final ('utf8' ); console .log (`解密后的数据: ${decrypted} ` );
公钥/私钥对 crypto 模块支持生成公钥/私钥对, 并提供签名和验证功能。
⭐⭐ 生成密钥对 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 const crypto = require ('crypto' );crypto.generateKeyPair ('rsa' , { modulusLength : 2048 , publicKeyEncoding : { type : 'spki' , format : 'pem' }, privateKeyEncoding : { type : 'pkcs8' , format : 'pem' , cipher : 'aes-256-cbc' , passphrase : 'top secret' } }, (err, publicKey, privateKey ) => { if (err) throw err; console .log (`公钥:\n${publicKey} ` ); console .log (`私钥:\n${privateKey} ` ); });
⭐⭐ 签名和验证 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const crypto = require ('crypto' );const sign = crypto.createSign ('RSA-SHA256' );sign.update ('Some data to sign' ); sign.end (); const signature = sign.sign (privateKey, 'hex' );console .log (`签名: ${signature} ` );const verify = crypto.createVerify ('RSA-SHA256' );verify.update ('Some data to sign' ); verify.end (); const isVerified = verify.verify (publicKey, signature, 'hex' );console .log (`验证结果: ${isVerified} ` );
密钥派生函数 crypto 模块支持 PBKDF2( Password-Based Key Derivation Function 2) 等密钥派生函数, 用于从密码生成密钥。
1 2 3 4 5 6 7 8 9 10 11 12 const crypto = require ('crypto' );const password = 'somepassword' ;const salt = crypto.randomBytes (64 );const iterations = 10000 ;const keylen = 32 ; const digest = 'sha256' ;crypto.pbkdf2 (password, salt, iterations, keylen, digest, (err, derivedKey ) => { if (err) throw err; console .log (`派生密钥: ${derivedKey.toString('hex' )} ` ); });
生成随机数 crypto 模块提供了安全的随机数生成函数, 适用于生成密钥、 IV 和其他需要高熵值的场合。
1 2 3 4 5 const crypto = require ('crypto' );const randomBytes = crypto.randomBytes (32 );console .log (`随机字节: ${randomBytes.toString('hex' )} ` );
stream 模块 stream 模块是处理流数据的核心工具, 它允许你以高效的方式处理大量数据, 而无需一次性将所有数据加载到内存中。
流( Stream) 是一种抽象接口, 用于表示能顺序读取或写入的数据源。 Node.js 提供了多种类型的流, 包括可读流( Readable) 、 可写流( Writable) 、 双工流( Duplex) 和转换流( Transform) 。
流的类型 ⭐⭐ 可读流: 从某个来源读取数据的流。 常见的例子包括从文件系统读取文件、 从网络连接读取数据等。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const { Readable } = require ('stream' );class MyReadable extends Readable { constructor (options ) { super (options); this .index = 1 ; } _read (size ) { const chunk = `${this .index++} \n` ; if (this .index > 5 ) { this .push (null ); } else { this .push (chunk); } } } const myReadable = new MyReadable ();myReadable.on ('data' , (chunk ) => { console .log (`接收到数据: ${chunk.toString()} ` ); }); myReadable.on ('end' , () => { console .log ('数据传输结束' ); });
⭐⭐ 可写流: 向某个目的地写入数据的流。 常见的例子包括写入文件系统、 发送数据到网络连接等。 1 2 3 4 5 6 7 8 9 10 11 12 13 const { Writable } = require ('stream' );class MyWritable extends Writable { _write (chunk, encoding, callback ) { console .log (`写入数据: ${chunk.toString()} ` ); callback (); } } const myWritable = new MyWritable ();myWritable.write ('Hello ' ); myWritable.write ('World!\n' ); myWritable.end ();
⭐⭐ 双工流: 同时实现了可读和可写的接口, 可以同时从某个来源读取数据并写入另一个目的地。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const { Duplex } = require ('stream' );class MyDuplex extends Duplex { _write (chunk, encoding, callback ) { console .log (`写入数据: ${chunk.toString()} ` ); callback (); } _read (size ) { const chunk = 'Some data\n' ; this .push (chunk); this .push (null ); } } const myDuplex = new MyDuplex ();myDuplex.on ('data' , (chunk ) => { console .log (`接收到数据: ${chunk.toString()} ` ); }); myDuplex.write ('Hello ' ); myDuplex.write ('World!\n' ); myDuplex.end ();
⭐⭐ 转换流: 是一种特殊的双工流, 它可以对输入数据进行某种形式的转换, 并将其作为输出数据。 常见的例子包括加密、 压缩、 解密、 解压缩等。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const { Transform } = require ('stream' );class MyTransform extends Transform { _transform (chunk, encoding, callback ) { const transformedChunk = chunk.toString ().toUpperCase (); this .push (transformedChunk); callback (); } } const myTransform = new MyTransform ();myTransform.on ('data' , (chunk ) => { console .log (`转换后的数据: ${chunk.toString()} ` ); }); myTransform.write ('hello world\n' ); myTransform.end ();
流的管道 流的一个强大特性是能够通过管道( piping) 将多个流串联起来。 这样可以轻松地构建复杂的数据处理流水线。
⭐⭐ 将可读流通过转换流再写入可写流 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 const { Readable , Writable , Transform } = require ('stream' );const readable = new Readable ({ read ( ) { this .push ('Hello World!\n' ); this .push (null ); } }); const transform = new Transform ({ transform (chunk, encoding, callback ) { const transformedChunk = chunk.toString ().toUpperCase (); this .push (transformedChunk); callback (); } }); const writable = new Writable ({ write (chunk, encoding, callback ) { console .log (`写入数据: ${chunk.toString()} ` ); callback (); } }); readable.pipe (transform).pipe (writable);
流的事件 流对象会触发各种事件, 你可以监听这些事件来处理特定的情况。
‘data’: 当有数据可读时触发。
‘end’: 当没有更多数据可读时触发。
‘error’: 当发生错误时触发。
‘finish’: 当所有数据已写入底层系统时触发。
‘close’: 当流或其底层资源被关闭时触发。
⭐⭐ 监听流的事件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const { Readable } = require ('stream' );const readable = new Readable ({ read ( ) { this .push ('Hello ' ); this .push ('World!\n' ); this .push (null ); } }); readable.on ('data' , (chunk ) => { console .log (`接收到数据: ${chunk.toString()} ` ); }); readable.on ('end' , () => { console .log ('数据传输结束' ); }); readable.on ('error' , (err ) => { console .error (`发生错误: ${err.message} ` ); });
常用方法 ⭐⭐ pipeline 是一种更安全的方式来连接多个流, 并确保它们在出现错误时正确关闭。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const { pipeline } = require ('stream' );const fs = require ('fs' );const zlib = require ('zlib' );pipeline ( fs.createReadStream ('input.txt' ), zlib.createGzip (), fs.createWriteStream ('input.txt.gz' ), (err ) => { if (err) { console .error ('管道出错:' , err.message ); } else { console .log ('文件已成功压缩为 Gzip 格式' ); } } );
⭐⭐ finished 方法用于等待流的所有操作完成( 包括数据读取、 写入和错误处理) 。 1 2 3 4 5 6 7 8 9 10 11 12 13 const { finished } = require ('stream' );const fs = require ('fs' );const rs = fs.createReadStream ('input.txt' );finished (rs, (err ) => { if (err) { console .error ('流操作出错:' , err.message ); } else { console .log ('流操作完成' ); } }); rs.resume ();
其他模块 子进程 用于创建子进程, 允许你在 Node.js 应用中执行外部命令或脚本, 并与它们进行通信。
1 2 3 4 5 6 7 8 9 10 11 12 13 const { exec } = require ('child_process' );exec ('ls -lh' , (err, stdout, stderr ) => { if (err) { console .error (`执行出错: ${stderr} ` ); return ; } console .log (`结果: ${stdout} ` ); });
字符串处理 1 2 3 4 5 6 7 8 9 10 11 const querystring = require ('querystring' );const unescaped = 'Hello World!' ;const escaped = querystring.escape (unescaped);console .log (escaped); const escaped2 = 'Hello%20World%21' ;const unescaped2 = querystring.unescape (escaped2);console .log (unescaped2);
逐行读取输入流 用于逐行读取输入流, 适合处理交互式命令行应用。
1 2 3 4 5 6 7 8 9 10 const readline = require ('readline' );const rl = readline.createInterface ({ input : process.stdin , output : process.stdout }); rl.question ('你叫什么名字? ' , (answer ) => { console .log (`你好, ${answer} !` ); rl.close (); });
vm 模块 用于在虚拟机环境中运行 JavaScript 代码, 适用于沙箱环境下的代码执行。
1 2 3 4 5 6 7 8 9 const vm = require ('vm' );const script = new vm.Script ('globalVar = "set by script"' );const sandbox = {};vm.createContext (sandbox); script.runInContext (sandbox); console .log (sandbox.globalVar );
dns 模块 用于解析域名系统( DNS) , 支持同步和异步查询。
1 2 3 4 5 6 7 8 const dns = require ('dns' );dns.lookup ('example.com' , (err, address, family ) => { console .log (`地址: ${address} 家族: IPv${family} ` ); });
tls 模块 提供传输层安全( TLS) 和安全套接字层( SSL) 协议的支持, 用于创建安全的网络连接。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const tls = require ('tls' );const fs = require ('fs' );const options = { key : fs.readFileSync ('server-key.pem' ), cert : fs.readFileSync ('server-cert.pem' ) }; const server = tls.createServer (options, (socket ) => { socket.write ('secure hello' ); socket.end (); }); server.listen (8000 , () => { console .log ('服务器正在监听端口 8000' ); });
events 模块 事件触发器模块, 提供了事件驱动编程的基本机制。
1 2 3 4 5 6 7 8 9 10 11 const EventEmitter = require ('events' );class MyEmitter extends EventEmitter {}const myEmitter = new MyEmitter ();myEmitter.on ('event' , () => { console .log ('事件触发!' ); }); myEmitter.emit ('event' );
Express Express 是 Node.js 上最流行的 WEB 应用框架之一, 属于第三方模块, 用于快速构建可扩展的网络应用和服务, 它是基于内置的 http 模块进一步封装出来的。
安装 1 2 3 4 npm i express npm i express@版本号
使用 1 2 3 4 5 6 7 8 9 10 11 const express = require ('express' );const app = express ();app.get ('/' , (req, res ) => { res.send ('Hello World!' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
路由 路由是指如何定义应用响应不同 URL 的方式。 Express 提供了强大的路由功能, 允许你定义各种 HTTP 方法( 如 GET、 POST 等) 的处理函数。
基本路由 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 app.get ('/' , (req, res ) => { res.send ('GET 请求到主页' ); }); app.post ('/' , (req, res ) => { res.send ('POST 请求到主页' ); }); app.put ('/user' , (req, res ) => { res.send ('PUT 请求到用户页面' ); }); app.delete ('/user' , (req, res ) => { res.send ('DELETE 请求到用户页面' ); });
动态路由 1 2 3 4 app.get ('/users/:userId/books/:bookId' , (req, res ) => { res.send (req.params ); });
链式调用 1 2 3 4 5 6 7 8 9 10 app.route ('/book' ) .get ((req, res ) => { res.send ('获取图书信息' ); }) .post ((req, res ) => { res.send ('添加新书' ); }) .put ((req, res ) => { res.send ('更新图书信息' ); });
模块化路由 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const express = require ('express' );const router = express.Router ();router.get ('/user/' , (req, res ) => { res.send ('用户列表' ); }); router.get ('user/:id' , (req, res ) => { res.send (`用户信息: ${req.params.id} ` ); }); module .exports = router;const express = require ('express' );const app = express ();const usersRouter = require ('./users' );app.use (usersRouter); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
中间件 中间件是 Express 应用的核心部分, 它是一些可以访问请求对象( req) 、 响应对象( res) 以及应用请求-响应周期中的下一个中间件函数的函数。
使用app.use()
函数注册全局中间件, 要放在所有路由之前注册。
内置中间件 ⭐⭐ req.query: 解析查询字符串, 可以直接使用, 不用注册 1 2 3 4 5 6 7 8 9 10 11 12 const express = require ('express' );const app = express ();app.get ('/search' , (req, res ) => { const query = req.query ; res.send (`查询参数: ${JSON .stringify(query)} ` ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ express.static: 用于提供静态文件服务的中间件 1 2 3 4 app.use (express.static ('public' )); app.use (express.static ('others' )); app.use ('/uploads' , express.static ('uploads' ));
⭐⭐ express.json: 用于解析 JSON 格式的请求体的中间件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const express = require ('express' );const app = express ();app.use (express.json ()); app.post ('/profile' , (req, res ) => { console .log (req.body ); res.send ('数据已接收' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ express.urlencoded: 用于解析 URL 编码格式的请求体的中间件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const express = require ('express' );const app = express ();app.use (express.urlencoded ({ extended : false })); app.post ('/login' , (req, res ) => { console .log (req.body ); res.send ('登录成功' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
第三方中间件 ⭐⭐ body-parser 用于解析请求体中的数据 1 2 3 4 npm install body-parser
1 2 3 4 5 6 7 8 9 10 11 12 const bodyParser = require ('body-parser' );app.use (bodyParser.json ()); app.use (bodyParser.urlencoded ({ extended : true })); app.post ('/login' , (req, res ) => { console .log (req.body ); res.send ('登录成功' ); });
⭐⭐ Helmet: 用户设置各种 HTTP 头以保护应用的安全中间件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 const express = require ('express' );const helmet = require ('helmet' );const app = express ();app.use (helmet ()); app.use (helmet ({ contentSecurityPolicy : { directives : { defaultSrc : ["'self'" ], scriptSrc : ["'self'" , "'unsafe-inline'" ] } } })); app.get ('/' , (req, res ) => { res.send ('这是一个安全的应用' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ morgan: 可以将每个请求的日志输出到终端或文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const express = require ('express' );const morgan = require ('morgan' );const fs = require ('fs' );const path = require ('path' );const app = express ();app.use (morgan ('dev' )); const accessLogStream = fs.createWriteStream (path.join (__dirname, 'access.log' ), { flags : 'a' });app.use (morgan ('combined' , { stream : accessLogStream })); app.get ('/' , (req, res ) => { res.send ('Hello World!' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ compression: 用于压缩响应内容, 减少传输的数据量, 从而加快页面加载速度。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const express = require ('express' );const compression = require ('compression' );const app = express ();app.use (compression ()); app.get ('/' , (req, res ) => { res.send ('<html><body><h1>这是一个压缩的响应</h1></body></html>' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ express-session: 用于管理用户的会话状态, 通常与身份验证一起使用。 1 npm install express-session
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const express = require ('express' );const session = require ('express-session' );const app = express ();app.use (session ({ secret : 'keyboard cat' , resave : false , saveUninitialized : true , cookie : { secure : false } })); app.get ('/' , (req, res ) => { if (req.session .views ) { req.session .views ++; res.setHeader ('Content-Type' , 'text/html' ); res.write ('<p>views: ' + req.session .views + '</p>' ); res.end (); } else { req.session .views = 1 ; res.end ('欢迎首次访问' ); } }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 const express = require ('express' );const multer = require ('multer' );const upload = multer ({ dest : 'uploads/' }); const app = express ();app.post ('/upload' , upload.single ('file' ), (req, res ) => { console .log (req.file ); console .log (req.body ); res.send ('文件已上传' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ express-rate-limit: 一个简单的限流中间件, 用于限制客户端的请求速率, 防止恶意攻击。 1 npm install express-rate-limit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const express = require ('express' );const rateLimit = require ('express-rate-limit' );const app = express ();const limiter = rateLimit ({ windowMs : 15 * 60 * 1000 , max : 100 }); app.use (limiter); app.get ('/' , (req, res ) => { res.send ('你可以每15分钟发送100次请求' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ serve-favicon: 用于提供网站的 favicon.ico 文件。 1 npm install serve-favicon
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 const express = require ('express' );const favicon = require ('serve-favicon' );const path = require ('path' );const app = express ();app.use (favicon (path.join (__dirname, 'public' , 'favicon.ico' ))); app.get ('/' , (req, res ) => { res.send ('首页' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ CORS (跨域资源共享)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const express = require ('express' );const cors = require ('cors' );const app = express ();app.use (cors ()); app.get ('/data' , (req, res ) => { res.json ({ message : '这是跨域资源' }); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
⭐⭐ CSRF (跨站请求伪造防护)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 const express = require ('express' );const cookieParser = require ('cookie-parser' );const csrf = require ('csurf' );const bodyParser = require ('body-parser' );const app = express ();app.use (cookieParser ()); app.use (bodyParser.urlencoded ({ extended : false })); const csrfProtection = csrf ({ cookie : true });app.get ('/form' , csrfProtection, (req, res ) => { res.send (`<form method="POST" action="/process">${csrfTokenInput(req)} </form>` ); }); function csrfTokenInput (req ) { return `<input type="hidden" name="_csrf" value="${req.csrfToken()} " />` ; } app.post ('/process' , csrfProtection, (req, res ) => { res.send ('数据已处理' ); }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
自定义中间件 自定义中间件必须有三个参数: (req, res, next), 要放在所有路由之前。 你可以使用它来处理特定的逻辑。
⭐⭐ 全局生效 1 2 3 4 app.use ((req, res, next ) => { console .log ("全局生效" ); next (); });
⭐⭐ 局部生效 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 const jb1 = (req, res, next ) => { console .log ("局部生效1" ); next (); }; const jb2 = (req, res, next ) => { console .log ("局部生效2" ); next (); }; app.get ('/' , jb1, jb2, (req, res ) => { res.send ('数据已处理' ); }); app.get ('/' , [jb1, jb2], (req, res ) => { res.send ('数据已处理' ); });
错误处理中间件 错误处理中间件必须有四个参数: (err, req, res, next), 要放在所有路由之后。 你可以使用它来捕获并处理应用中的错误。
1 2 3 4 app.use ((err, req, res, next ) => { console .error (err.stack ); res.status (500 ).send ('服务器发生错误' ); });
Session express-session 是一个用于管理用户会话的中间件, 广泛应用于基于 Express 的应用中。 它通过在服务器端存储会话数据, 并在客户端设置一个会话标识符( 通常是通过 cookie) , 来跟踪用户的会话状态。
安装 1 npm install express-session
配置 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 const express = require ('express' );const session = require ('express-session' );const app = express ();app.use (session ({ secret : 'keyboard cat' , resave : false , saveUninitialized : true })); app.get ('/' , (req, res ) => { if (req.session .views ) { req.session .views ++; res.setHeader ('Content-Type' , 'text/html' ); res.write ('<p>views: ' + req.session .views + '</p>' ); res.end (); } else { req.session .views = 1 ; res.end ('欢迎首次访问' ); } }); const PORT = process.env .PORT || 3000 ;app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); });
存储器 默认情况下, express-session 使用内存存储器来保存会话数据。 然而, 在生产环境中, 建议使用持久化存储器, 以确保会话数据不会丢失。 常见的存储器实现包括: MemoryStore( 不推荐用于生产环境) 、 RedisStore、 MongoDBStore。
1 npm install redis connect-redis
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 const express = require ('express' );const session = require ('express-session' );const RedisStore = require ('connect-redis' )(session);const redis = require ('redis' );const redisClient = redis.createClient ({ url : 'redis://localhost:6379' }); redisClient.connect ().then (() => { const app = express (); app.use (session ({ store : new RedisStore ({ client : redisClient }), secret : 'keyboard cat' , resave : false , saveUninitialized : true , cookie : { maxAge : 60000 , secure : false , httpOnly : true , sameSite : 'lax' } })); app.get ('/' , (req, res ) => { if (req.session .views ) { req.session .views ++; res.setHeader ('Content-Type' , 'text/html' ); res.write ('<p>views: ' + req.session .views + '</p>' ); res.end (); } else { req.session .views = 1 ; res.end ('欢迎首次访问' ); } }); const PORT = process.env .PORT || 3000 ; app.listen (PORT , () => { console .log (`服务器正在监听端口 ${PORT} ` ); }); }).catch (console .error );
会话数据 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 app.get ('/login' , (req, res ) => { req.session .user = { id : 1 , name : 'Alice' }; res.send ('登录成功' ); }); app.get ('/profile' , (req, res ) => { if (req.session .user ) { res.send (`你好, ${req.session.user.name} ` ); } else { res.send ('请先登录' ); } }); app.get ('/logout' , (req, res ) => { delete req.session .user ; res.send ('已注销' ); });
销毁会话 1 2 3 4 5 6 7 8 app.get ('/logout' , (req, res ) => { req.session .destroy ((err ) => { if (err) { return res.send ('注销失败' ); } res.send ('已注销' ); }); });
事件监听 1 2 3 4 5 6 7 app.use ((req, res, next ) => { req.session .on ('destroy' , () => { console .log ('会话已销毁' ); }); next (); });
JWT 在Express应用中, JWT( JSON Web Token) 通常用于用户认证和信息交换。
安装 1 2 3 4 5 npm install jsonwebtoken npm install express-jwt
生成JWT 1 2 3 4 5 const jwt = require ('jsonwebtoken' );const secretKey = 'your_secret_key' ; const token = jwt.sign ({ userId : 123 }, secretKey, { expiresIn : '1h' });console .log (token);
验证JWT 1 2 3 4 5 6 7 jwt.verify (token, secretKey, (err, decoded ) => { if (err) { console .log ('Token无效:' , err); return ; } console .log ('Token解析:' , decoded); });
路由拦截 1 2 3 4 5 6 7 8 9 10 11 const expressJwt = require ('express-jwt' );const secretKey = 'your_secret_key' ;app.use (expressJwt ({ secret : secretKey }).unless ({ path : ['/login' , '/public' ] })); app.get ('/profile' , (req, res ) => { res.send (`欢迎, ${req.user.userId} ` ); });
错误处理 1 2 3 4 5 6 7 app.use ((err, req, res, next ) => { if (err.name === 'UnauthorizedError' ) { res.status (401 ).send ('非法访问' ); } });
视图引擎 Express 支持多种模板引擎来渲染 HTML 页面。 常见的模板引擎包括 EJS、 Pug 和 Handlebars。
安装
使用 ⭐⭐ 创建一个路由 1 2 3 4 5 6 app.set ('view engine' , 'pug' ); app.set ('views' , './views' ); app.get ('/' , (req, res ) => { res.render ('index' , { title : 'Express' , message : 'Hello there!' }); });
⭐⭐ 添加配置 1 2 3 4 5 6 # 然后在 views 目录下创建一个 index.pug 文件 html head title=title body h1=message
数据库 在 Node.js 中与 MySQL 数据库进行交互, 通常会使用 mysql 或 mysql2 模块。 这两个模块提供了相似的功能, 但 mysql2 在性能和功能上有一些改进。
安装
简单使用 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 const mysql = require ('mysql' );const connection = mysql.createConnection ({ host : 'localhost' , user : 'root' , password : 'password' , database : 'test_db' }); connection.connect ((err ) => { if (err) { console .error ('连接失败:' , err.stack ); return ; } console .log ('成功连接到数据库' ); }); connection.query ('SELECT 1 + 1 AS solution' , (error, results, fields ) => { if (error) throw error; console .log ('结果:' , results[0 ].solution ); }); connection.end ();
连接池 为了提高性能和资源利用率, 建议使用连接池而不是直接创建单个连接。 连接池允许多个请求共享一组数据库连接, 从而减少频繁建立和关闭连接的开销。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 const mysql = require ('mysql' );const pool = mysql.createPool ({ host : 'localhost' , user : 'root' , password : 'password' , database : 'test_db' , waitForConnections : true , connectionLimit : 10 , queueLimit : 0 }); pool.query ('SELECT 1 + 1 AS solution' , (error, results, fields ) => { if (error) throw error; console .log ('结果:' , results[0 ].solution ); }); pool.end ();
事务处理 事务允许你将多个 SQL 语句作为一个原子操作来执行, 确保数据的一致性和完整性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 const mysql = require ('mysql' );const connection = mysql.createConnection ({ host : 'localhost' , user : 'root' , password : 'password' , database : 'test_db' }); connection.connect (); connection.beginTransaction ((err ) => { if (err) { throw err; } connection.query ('INSERT INTO accounts (name, balance) VALUES (?, ?)' , ['Alice' , 100 ], (error, results, fields ) => { if (error) { return connection.rollback (() => { throw error; }); } connection.query ('UPDATE accounts SET balance = balance - ? WHERE name = ?' , [50 , 'Alice' ], (error, results, fields ) => { if (error) { return connection.rollback (() => { throw error; }); } connection.commit ((error ) => { if (error) { return connection.rollback (() => { throw error; }); } console .log ('事务提交成功' ); }); }); }); }); connection.end ();
流式查询 对于大数据集, 可以使用流式查询来逐步读取数据, 避免一次性加载大量数据导致内存溢出。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 const mysql = require ('mysql' );const connection = mysql.createConnection ({ host : 'localhost' , user : 'root' , password : 'password' , database : 'test_db' }); connection.connect (); const query = connection.query ('SELECT * FROM large_table' );query.on ('error' , (err ) => { console .error ('查询错误:' , err); }); query.on ('fields' , (fields ) => { console .log ('字段:' , fields); }); query.on ('result' , (row ) => { console .log ('行:' , row); }); query.on ('end' , () => { console .log ('查询结束' ); }); connection.end ();
预处理语句 预处理语句可以防止 SQL 注入攻击, 并且在重复执行相同查询时提高性能。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const mysql = require ('mysql' );const connection = mysql.createConnection ({ host : 'localhost' , user : 'root' , password : 'password' , database : 'test_db' }); connection.connect (); const userId = 1 ;const userName = 'Alice' ;const query = 'SELECT * FROM users WHERE id = ? AND name = ?' ;connection.query (query, [userId, userName], (error, results, fields ) => { if (error) throw error; console .log ('查询结果:' , results); }); connection.end ();
热更新 安装
使用 1 2 3 4 5 node index.js nodemon index.js
学习资源