Node.js相关


JS 是客户端编程语言,通过 Node.js,JS也可以服务端语言被使用。

使用 npm 初始化新项目,命令行工具运行: npm init

根据提示输入 package name、version number、description。通过 enter 键跳过,最终生成 package.json 文件。

检查 node 版本

node -v

偶数版本号的为稳定版

命令行工具输入 node,进入 Node.js 环境。连续2次 Ctrl+C 退出 Node.js 环境。

在命令行模式下运行 .js 文件和在 Node.js 环境下直接运行 JavaScript 代码展示效果不同。

Node.js 环境每输入一行代码就执行一行(每行 JavaScript 代码的结果会自动打印出来),直接运行 JavaScript 文件,相当于一次性执行所有源代码,除非使用console打印,否则输出没有显示。

单线程执行

Node.js不断执行响应事件的JavaScript函数,直到没有任何响应事件的函数可以执行时退出。

通过调用 process.nextTick() 可以在下一次事件响应中执行相应代码。

模块

在Node环境中,一个.js文件就称之为一个模块(module)。使用模块的好处:提高了代码的可维护性,避免函数名和变量名冲突。

Node.js 利用 JavaScript 的函数式编程的特性,使用闭包实现模块的隔离。

模块输出: module.exports = 变量名

Node 在加载js文件前先准备一个对象 module,并将其作为函数参数传入加载函数,

模块引用: var 变量名 = require('./文件A');

Node 保存了所有导入的 module,当我们用 require()获取module时,Node找到对应的module,把这个module的 exports 变量返回

上面表示模块的相对路径,即在当前目录下的A文件。如果去掉 ./,则依次在内置模块、全局模块和当前模块下查找A文件。

Node.js内置的常用模块就是为了实现服务器程序的基本功能:接收网络请求,读写文件,处理二进制内容。

import Router from ‘vue-router’

能够正确引用 mode_modules 目录下的文件的原理是什么?以及具体引用哪个文件?

首先看知乎 答案,然后看 Node.js 官方文档

如何寻找 mode_modules 目录下的文件Loading from node_modules Folders,加载哪一个文件Folders as Modules

知道了模块引用原理,可以对第三方包进行 debugger

内置对象

JavaScript有且仅有一个全局对象,在Node.js环境中,这个对象叫 global.

process 表示当前Node.js进程:可以用来查看当前系统信息,node版本。

> process.platform
'win32'
> process.arch
'x64'
> process.version
'v12.14.0'

fs

该模块为文件系统模块,同时通过了异步和同步的方法。

因为JavaScript的单线程模型,执行IO操作时,使用异步方法的JavaScript代码无需等待,而是传入回调函数后,继续执行后续JavaScript代码.

通过 fs.stat(filepath, callback) 可以获取文件的信息(大小、创建时间、修改时间等)。

同步读文件

var fs = require('fs');
var data = fs.readFileSync('sample.txt', 'utf-8');
console.log(data);

因为函数直接返回结果,需要用 try…catch 捕获文件读取发生的错误.

异步读文件

var fs = require('fs');

fs.readFile('sample.txt', 'utf-8', function (err, data) {
  if (err) {
      console.log(err);
  } else {
      console.log(data);
  }
});

Node.js标准的回调函数:第一个参数代表错误信息,第二个参数代表结果。

当正常读取时,err 参数为 null,data 参数为读取到的String。当读取发生错误时,err 参数代表一个错误对象,data 为 undefined.

当读取二进制文件时,不传入文件编码(第二个参数)时,回调函数的 data 参数将返回一个 Buffer 对象。

Node.js 提供了Buffer对象和String互相转换的方法。

异步写入文件

var fs = require('fs');
var result = { 'id': 1 };

fs.writeFile('./result.json', JSON.stringify(result), (err) => {
  if (err) {
    // 报错:
    // 意外错误
    // 文件权限问题
    // 文件夹找不到(不会自动创建文件夹)
    console.log(err);
  } else {
    console.log('success');
  }
});

第二个参数表示传入的数据, 如果其类型为 String,默认按 UTF-8 编码写入文本文件;如果传入的参数是 Buffer,则写入的是二进制文件.

stream

该模块用来支持“流”这种数据结构。

流的特点是数据是有序的,而且必须依次读取,或者依次写入,不能像Array那样随机定位。

在 Node.js中,流是一个对象,通常是文件流。

以流的形式读取文件,通过响应流的事件:data 事件表示流的数据已经可以读取了(该事件可以用有多次,每次传入的chunk是流的一部分),end 事件表示没有数据可以读取了,error 事件表示出错了。

// 打开一个流:
var rs = fs.createReadStream('sample.txt', 'utf-8');

以流的方式写入文件,通过调用 write() 方法,最后以 end() 结束。

// 写入一个流
var ws1 = fs.createWriteStream('output1.txt', 'utf-8');
ws1.write('使用Stream写入文本数据...\n');
ws1.write('END.');
ws1.end();

通过 pipe() 方法把一个 Readable 文件流和另一个 Writable 文件流串起来,可实现复制文件内容(后者内容完全被覆盖)。

http

该模块提供的 requestresponse 对象。前者的属性和方法可以拿到 HTTP 请求的信息,后者的方法可以把 HTTP 响应返回浏览器。

path

该模块可以用来方便地构建操作系统的文件路径。

var path = require('path');
// 解析当前目录:
var workDir = path.resolve('.');
// 拼接本地文件路径
var filepath = path.join(workDir, 'index.html');
// d:\xue_w\Documents\dive-into-web\index.html

crypto

Nodejs用C/C++实现通用的加密和哈希算法,通过 cypto 这个模块暴露为JavaScript接口提供,使用方便,运行速度快。

crypto模块也可以处理数字证书,通常用在SSL连接。一般情况下,https连接只需要处理服务器端的单向认证,如无特殊需求(例如自己作为Root给客户发认证证书),建议用反向代理服务器如Nginx等Web服务器去处理证书。

const crypto = require('crypto');
// 如果要使用SHA1,把md5换成 SHA1 即可
const hash = crypto.createHash('md5');

// 可任意多次调用update(),默认输入字符串编码为UTF-8,也可以传入Buffer
hash.update('Hello, world!');
hash.update('Hello, nodejs!');

console.log(hash.digest('hex')); // 7e1977739c748beac0c0fd14fd26a544

还可以使用更安全的 sha256、sha512。

对称加密算法 AES

加解密使用同一个密钥,需要自己封装函数。加密结果通常有两种表示方法:hex 和 base64。当通信双方使用不同语言时,要确认双方是否遵循同样的AES算法,字符串密钥、IV是否相同,加密后的数据格式是否统一。

非对称加密算法 RSA

由一个私钥和一个公钥构成的密钥对,通过私钥加密,公钥解密,或者通过公钥加密,私钥解密。

web开发框架

Express 是第一代Node.js web框架,基于ES5的语法,通过回调实现异步代码。Express团队基于ES6重新编写了下一代框架,即koa1。目前,该团队已基于ES7编写了koa2,完全使用 Promise 配合 async 来实现异步。

koa2

每收到一个http请求,koa就会调用通过 app.use() 注册的 async 函数,然后用await next()来调用下一个async函数。每个async函数称为 middleware,这些 middleware 可以组成处理链,依次完成相应的任务。

注意:调用 app.use() 的顺序决定了 middleware

如果一个 middleware 没有调用 await next(),那么后续的middleware将不再执行。

app.use(async (ctx, next) => {
  if (await checkUserPermission(ctx)) {
    await next();
  } else {
    // 用户权限校验不通过,则直接返回
    ctx.response.status = 403;
  }
});

常用的middleware:

  • koa-router,负责处理URL映射的middleware
  • koa-bodyparser,解析原始request请求,然后,把解析后的参数,绑定到ctx.request.body中(不论Node.js提供的原始request对象,还是koa提供的request对象,都没提供解析request的body的功能)

模板引擎

基于模板,根据输入的数据,输出文本的一个组件。通常是输出HTML文本,也可以是Text,XML,Markdown等。

通常需要具备的功能:

  • 对特殊字符进行转义,如 <scrit> 标签
  • 格式化,如货币、日期时间值展示
  • 支持简单的逻辑,如:条件判断、循环输出等
  • 模板继承

MVC

最初接触web编程时学习的概念:Model-View-Controller,中文“模型-视图-控制器”。Controller 负责业务逻辑,如:数据库操作,表单提交校验。View 是人看到的一切,比如:模版、HTML页面、CSS样式、JavaScript脚本。负责显示逻辑,替换变量输出用户最终看到的页面。Model 模型即所有数据存储的地方,如:数据库、全局字典。是传给 View 的JS数据对象。

Sequelize数据库

常见的付费数据库有Oracle、SQL Server;免费的有 MySQL、PostgreSQL、sqlite。其中MySQL普及率最高。

访问MySQL是通过网络发送SQL命令给MySQL服务器。这个访问MySQL服务器的软件包通常称为 MySQL 驱动程序。MySQL官方提供了Java、.Net、Python、Node.js、C++和C的驱动程序,官方的 Node.js 驱动目前仅支持5.7以上版本。

数据库每一行数据都可以用一个JavaScript对象表示,这就是传说中的ORM技术:Object-Relational Mapping,把关系数据库的表结构映射到对象上。

Sequelize是Node.js的ORM框架

实战

读取命令行参数

http://nodejs.cn/learn/nodejs-accept-arguments-from-the-command-line

循环打印所有的参数(包括 node 路径和文件路径):

process.argv.forEach((val, index) => {
  console.log(`${index}: ${val}`)
})
node test.js m 20220609

0: /Users/*/.nvm/versions/node/v16.14.0/bin/node
1: /Users/*/path_to_file/update-theme-name.js
2: m
3: 20220609

仅获取所需参数,改进下:

const args = process.argv.slice(2)
console.log(args[0], args[1])