node.js
1
2
3
4
5
6
7
// 基于Chrome v8 的js运行环境
// 使用javascript的开发平台
// js框架库
1. 基于 [Express 框架](http://www.expressjs.com.cn/),可以快速构建 `Web` 应用
2. 基于 [Electron 框架](https://electronjs.org/),可以构建跨平台的桌面应用
3. 基于 [restify 框架](http://restify.com/),可以快速构建 `API` 接口项目
4. 读写和操作数据库、创建实用的命令行工具辅助前端开发、etc…
终端命令
1
2
3
4
5
6
7
8
9
10
11
12
13
// cmd
esc // 清除当前命令
cls // 清空命令行
tab // 路径补全
dir // 查看目录
cd.>文件 // 创建文件
md // 创建文件夹

在文件地址栏直接cmd可以打开当前目录路径的cmd终端窗口

// powershell
shift+右键 打开powershell终端
New-Item 文件 // 新建文件
文件读写模块(fs)
1
2
3
4
5
6
7
File system // 文件系统   fs不是全局模块所以需要加载

var fs = require('fs') // 加载模块
readFile // 读文件
writeFile // 写文件
mkdir // 创建文件夹
readdirSync // 获取文件夹内文件名字
文件写入
1
2
3
4
5
6
7
8
9
10
11
12
13
fs.writeFile(file, data[, options], callback) // 异步操作

fs.writeFile('./hello.txt',msg,'utf8',function(err){
// body...
// 如果 err === null,表示写入文件成功,没有错误!
// 只要 err里面不是null,就表示写入文件失败了!
if(err){
console.log('写文件出错了! 具体错误:' + err);
}else{
console.log('ok');
}
});
// 如果目录存在就可以自动创建文件
文件读取
1
2
3
4
5
6
7
8
9
10
11
fs.readFile(path[, options], callback) // 异步操作

// 在读取文件的时候,如果传递了编码,那么回调函数中的data默认就会转换为字符串
fs.readFile('./hello.txt','utf8',function(err,data){
if(err){
throw err;
}
// data 参数的数据类型是一个 Buffer 对象,里面保存的就是一个一个的字节 (理解为字节数组)
// 把 buffer 对象转换为字符串,调用 toString() 方法
console.log(data.toString('utf8')); // 默认utf8
})
创建文件夹
1
fs.mkdir(path[, mode], callback) // mode 是权限
获取文件名字
1
fs.readdirSync(path[, options]) // 返回一个不包括 '.' 和 '..' 的文件名的数组
解决在文件读取中 ./ 相对路径的问题
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 此处的 ./ 相对路径,相对的是执行ndoe命令的路径
// 而不是相对于正在执行的这个js文件来查找hello.txt
fs.readFile('./hello.txt','utf8',function(err,data){
if(err){
throw err;
}
console.log(data)
})

// 解决:__dirname,__filename 并非全局,而是模块作用域下的
// __dirname: 表示,当前正在执行的js文件所在的目录
// __filename: 表示,当前正在执行的js文件的完整路径

var fs = require('fs');
var filename = __dirname + '\\' + 'hello.txt'; // 但是跨平台并不好

Path模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 加载path模块  path.join([...paths]) 
const path = require('path');
var filename = path.join(__dirname,'hello.txt'); // path.join(__dirname,文件夹,'hello.txt');

fs.readFile(filename,'utf8',function(err,data){
if(err){
throw err;
}
console.log(data)
})

// path.sep 当前操作系统的文件路径分隔符
// path.join() 会自动识别当前运行的操作系统文件路径分隔符,帮我们处理好
// 跨平台移植性好


path.basename(路径) // 快速获取文件路径中的文件名
path.extname(路径) // 用来获取文件路径中的文件扩展名
创建目录
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var fs = require('fs');

fs.mkdir('test-mkdir',function(err){
if(err){
console.log('创建目录出错了,详细信息如下:');
console.log(err);
}else{
console.log('目录创建成功!');
}
})

fs.mkdir('根目录',function(err){
if(err){
throw err;
}
fs.mkdir('./根目录/子目录1');
fs.mkdir('./根目录/子目录2');
fs.mkdir('./根目录/子目录3');
fs.mkdir('./根目录/子目录4');
})
错误优先
1
error-first // 回调函数第一个参数是错误对象
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
// 创建一个简单的http服务器程序

// 1. 加载http模块
var http = require('http');

// 2. 创建一个http服务对象
var server = http.createServer();

// 3. 监听用户的请求事件(request事件)
// request请求对象 包含了用户请求报文中的所有内容,通过request对象可以获取所有用户提交过来的数据
// req.url 是客户端请求的URL地址 端口号后面的
// req.method 获取请求客户端所使用请求方法(POST,GET ...)

// response响应对象 用来向用户响应一些数据,当服务器要向客户端响应数据的时候必须使用response对象
// 有了 request对象和response对象,就既可以获取用户提交的数据,也可以向用户响应数据了
// res.end() 向客户端响应一些内容,并结束此次请求

server.on('request',function(req,res){
res.write('Hello World!!!');
// 对于每一个请求,服务器必须结束响应,否则客户端(浏览器) 会一直等待服务器响应结束
res.end();
});


// 4. 启动服务
server.listen(8080,function(){
console.log('服务器启动了,请访问:http://localhost:8080');
});


var http = require('http');
http.createServer(function(req,res){
res.end();
}).listen(8080,function(){
console.log('http://localhost:8080');
});

解决中文乱码
1
2
// 解决乱码的思路,服务器通过设置http响应报文头,告诉浏览器使用相应的编码来解析网页
res.setHeader('Content-Type','text/plain;charset=utf-8'); // text/plain 纯文本 编码utf-8
根据用户不同请求,做出不同响应(响应现有的 HTML 文件)
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
// 根据用户不同请求,做出不同响应(响应 现有的 HTML 文件)

// 加载http模块
var http = require('http');
// 加载fs模块
var fs = require('fs');
// 加载 path 模块
var path = require('path');

// 创建 http 服务,并启动该服务
http.createServer(function(req,res){
// 通过 req.url 获取用户请求的路径,根据不同的请求路径服务器做出不同的响应
if(req.url === '/' || req.url === '/index'){
// 读取 index.html 文件
fs.readFile(path.join(__dirname,'htmls','index.html'),function(err,data){
if(err){
throw err;
}
// 把读取到的index.html 中的内容直接发送给浏览器
res.end(data);
})
}else if(req.url === '/login'){
fs.readFile(path.join(__dirname,'htmls','login.html'),function(err,data){
if(err){
throw err;
}
res.end(data);
})
}else{
fs.readFile(path.join(__dirname,'htmls','404.html'),function(err,data){
if(err){
throw err;
}
res.end(data);
})
}
}).listen(9090,function(){
console.log('http://localhost:9090');
});
响应图片
1
2
3
4
5
6
7
8
9
10
else if(req.url === '/images/index.jpg'){
// 表示用户要请求 images下的index.jpg图片
fs.readFile(path.join(__dirname,'images','index.jpg'),function(err,data){
if(err){
throw err;
}
res.setHeader('Content-Type','image/jpeg');
res.end(data);
})
}
响应css
1
2
3
4
5
6
7
8
9
10
else if(req.url === '/css/index.css'){
// 表示用户要请求 css下的index.css
fs.readFile(path.join(__dirname,'css','index.css'),function(err,data){
if(err){
throw err;
}
res.setHeader('Content-Type','text/css');
res.end(data);
})
}
自定义模块
1
2
const m1 = require('./mi.js');
// 可以省略.js的后缀名
向外共享
1
2
3
4
5
6
module.exports // 向 module.exports 对象上挂载之后 可以共享出去属性和方法

// exprots和module.exports指向同一个对象 写的简单些

// 默认情况下module.exports 和exports指向同一个对象,但是,如果他们指向不同的对象时,最终导出的结果以module.exports为准
// 不要混着用
moment模块
1
第三方格式化时间模块
package.json和package-lock.json
1
2
// package-lock.json 是记录所需依赖关系和下载信息的文件   下载依赖更快
// package.json 是记录本地项目的相关信息 下载需要检索 慢
mime模块
1
2
3
4
npm install mime
const mime = require('mime');
mime.getType('txt'); // ⇨ 'text/plain'
mime.getExtension('text/plain'); // ⇨ 'txt'
获取一个目录下的所有静态资源
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
// 模拟Apache
// 加载http模块
var http = require('http');
var path = require('path');
var fs = require('fs');
var mime = require('mime');

// 创建服务
http.createServer(function(req,res){
// 1. 获取用户请求的路径
// req.url
// /css/index.css
// /images/index.png

// 2. 获取 public 目录的完整路径
var publicDir = path.join(__dirname,'public');

// 3. 根据 public 的路径和用户请求的路径,最终计算出用户请求的静态资源的完整路径
var filename = path.join(publicDir,req.url);
// console.log(filename);

// 4. 根据文件的完整路径去读取该文件,如果读取到了,则把文件返回给用户,如果读取不到,则返回404
fs.readFile(filename,function(err,data){
if(err){
res.end('文件不存在 404');
}else{

// 通过第三方模块 mine,来判断不同的资源对应的 Content-Type 的类型
res.setHeader('Content-Type',mime.getType(filename));
// 如果找到了用户要读取的文件,那么直接把该文件返回给用户
res.end(data);
}
})
// res.end('over');

}).listen(9090,function(){
console.log('http://localhost:9090');
})
对于服务器来说URL请求就是一个标识符
1
2
3
4
5
6
7
8
9
else if(req.url === '/haha.xxx'){
fs.readFile(path.join(__dirname,'index.jpg'),function(err,data){
if(err){
throw err;
}
res.setHeader('Content-Type','image/jpeg')
res.end(data);
});
}
request 和 response 对象介绍
1
2
3
// request: 服务器解析用户提交的http请求报文,将结果解析到request对象中。凡是要获取和用户相关的数据都可以通过request对象获取

// response: 在服务器端用来向用户做出响应的对象。凡是需要向用户(客户端)响应的操作,都需要通过response对象来进行。
request 对象
1
2
3
4
5
6
7
request 对象类型 <http.IncomingMessage>,继承自stream.Readable
request 对象常用成员
request.headers // 获取所有请求报文头 返回的是一个对象,这个对象中包含了所有的请求报文头
request.rawHeader // 获取原生请求报文头 返回的是一个数组,数组中保存的都是请求报文头的字符串
request.httpVersion // 获取HTTP协议版本号
request.method // 获取请求客户端所使用请求方法(POST,GET ...)
request.url // 获取这次请求的路径(获取请求报文中的请求路径,不包含主机名称,端口号,协议)
response对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
1. res.write()
2. 每个请求都必须要调用的一个方法 res.end();
结束响应(请求)
告诉服务器该响应的报文头,报文体等等全部已经响应完毕,可以考虑本次响应结束。
res.end() 要响应数据的话,数据必须是String类型或者是Buffer类型
4. 通过 res.setHeader() 来设置响应报文头
// res.setHeader() 要放在res.write() 和 res.end() 之前设置
// 因为即使我们不设置响应报文头,系统也会默认有响应报文头,并且默认发送给浏览器,当已经发送过响应报文头后,就不能再通过res.setHeader() 来再次设置响应报文头了
// 否则就会报错
// res.setHeader('Content-Type','text/plain;charset=utf-8');
5. 设置http响应状态码
// res.statusCode 设置 http 响应状态码
// res.statusMessage 设置 http 响应状态码对应的消息
// res.statusCode = 404;
// res.statusMessage = 'Not Found';
6. res.writeHead()
// 直接向客户端响应(写入) http 响应报文头
// 建议在res.write() 和 res.end() 之前设置

// res.writeHead(res.statusCode,res.statusMessage,{})

res.writeHead(404,'Not Found',{
'Content-Type':'text/html;charset=utf-8'
});
NPM全局安装
1
2
3
4
5
npm install 包名 -g // npm全局安装指的是把包安装成了一个命令行工具。

npm install mime -g // 通过npm全局安装mime

mime a.txt // 安装完毕后可以在命令行中直接使用
NPM常用命令
1
2
3
4
5
6
7
8
1. install,安装包。npm install 包名
// 简写 install i 不带包名可以用来安装模块依赖的包
2. uninstall,卸载包。npm uninstall 包名
3. version,查看当前npm版本。npm version 或 npm -v
4. init,创建一个package.json文件(包描述文件,元数据,有这个文件才是包)。npm init
5. 注意:当使用 npm init -y 的时候,如果当前文件夹(目录)的名字比较怪(有大写,有中文等等)就会影响 npm init -y 的一步生成操作,此时需要 npm init 根据向导来生成

npm uninstall 具体包名 // 卸载包 也会从package.json中删除 简写 npm un
npm安装版本号
1
2
3
第一位数字 大版本
第二位数字 功能版本
第三位数字 bug修复版本
包的分类
1
2
3
4
5
6
7
8
9
// 开发依赖包(被记录到 devDependencies 节点中的包,只在开发期间会用到)
npm i 包名 -D
npm i --save-dev

// 核心依赖包(被记录到 dependencies 节点中的包,在开发期间和项目上线之后都会用到)
npm install 包名
npm i 包名
npm i --save 包名
npm i -S 包名
解决npm下包速度慢的问题
1
2
3
4
5
6
7
8
9
// npm config get registry
// 查看当前的下包镜像源

// npm config set registry=https://registry.npm.taobao.org/ 将下包的镜像源切换为淘宝镜像源

// npm config get registry
// 检查镜像源是否下载成功

// https://registry.npmjs.org/ 默认的
nrm
1
2
3
4
5
// 为了更方便的切换下包的镜像源,我们可以安装 nrm 这个小工具,利用 nrm 提供的终端命令,可以快速查看和切换下包的镜像源。

npm i nrm -g // 安装为全局
nrm ls // 查看镜像源
nrm use taobao // 切换镜像源
i5ting_toc
1
2
3
4
// i5ting_toc 是一个可以把 md 文档转为 html 页面的小工具,使用步骤如下:

npm install -g i5ting_toc
i5ting_toc -f 要转换的md文件路径 -o
包的结构
1
2
3
4
一个规范的包,它的组成结构,必须符合以下 3 点要求:
1. 包必须以单独的目录而存在
2. 包的顶级目录下要必须包含 package.json 这个包管理配置文件
3. package.json 中必须包含 name,version,main 这三个属性,分别代表包的名字、版本号、包的入口。
发包相关命令
1
2
3
4
5
6
npm login // 登录
npm whoami // 查看当前登录用户名

npm publish // 发布
npm unpublish // 删除已发布的包
npm unpublish 包名 --force
Express
1
npm install express
创建基本web服务器
1
2
3
4
5
6
7
8
9
// 1.导入 express
const express = require('express')
// 2. 创建 web 服务器
const app = express()

// 3. 调用 app.listen(端口号, 启动后的回调函数), 启动服务器
app.listen(3000, () => {
console.log('running……')
})
监听 GET 和 POST 请求,并响应客户端
1
2
3
app.get('/', (req, res) => res.send('Hello World!')) 
app.post('/', (req, res) => res.send('Hello World!'))
// 可以响应JSON对象
获取 URL 中携带的查询参数
1
2
3
4
5
6
app.get('/', (req, res) => {
// 通过 req.query 可以获取到客户端发送过来的,查询参数
// 注意:默认情况下, req.query 是一个空对象
console.log(req.query)
res.send(req.query)
})
获取URL的的动态参数
  • /:id – id 值不是固定的,可以自己定义,例如: /:ids
  • 展示到页面中的 id 键,是自定义的变量值
  • 参数可以有多个,例如: /:ids/:name
1
2
3
4
5
app.get('/user/:id', (req, res) => {
// req.params 是动态匹配到的 URL 参数,默认也会是一个空对象
console.log(req.params)
res.send(req.params)
})
托管静态资源目录
1
2
3
4
5
6
7
app.use(express.static('public'))

app.use(express.static('public'),express.static('public'))
// 挂载多个

// 挂载路径前缀
app.use('public',express.static('public'))
路由
1
2
// 在 Express 中,路由指的是请求地址和服务器处理函数之间的映射关系
// 在 Express 中,路由分三部分 请求的类型、请求的 URL 地址、处理函数
路由模块化
  1. 创建路由模块对应的 .js 文件
  2. 调用 express.Router() 函数创建路由对象
  3. 向路由对象上挂载具体的路由
  4. 使用 module.exports 向外共享路由对象
  5. 使用 app.use() 函数注册路由模块
express.Router()
1
2
express.Router() // 函数创建路由对象
// 向路由对象上挂载具体的路由
app.use()
1
2
3
4
5
// 注册全局中间件(没有挂载前缀的)
app.use((req,res,next)=>{
console.log('全局中间件函数被触发了')
next() // 放行函数 不调用将不会前往下一个中间件
})
express中间件
所谓的中间件(Middleware ),特指业务流程的中间处理环节
1
2
3
// express的中间件 本质上就是一个 function 处理函数
// next 函数是实现多个中间件连续调用的关键,它表示把流转关系转交给下一个中间件或路由
// 区别 路由函数 和 中间件函数 就是看参数是否包含next
局部生效的中间件
1
2
3
4
5
6
const fn = function(req,res,next){
console.log('局部中间件函数被触发了');
next();
}

app.post('/',fn,function(req,res){});
中间件可以调用多个
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// 定义中间件函数 mv1
const mv1 = (req, res, next) => {
console.log('这是第一个中间件函数')
next()
}
// 定义中间件函数 mv2
const mv2 = (req, res, next) => {
console.log('这是第二个中间件函数')
next()
}

// mv1、mv2 这个中间件只在 "当前路由中生效",这种用法属于 "局部生效的中间件"
app.get('/', mv1, mv2, (req, res) => {
res.send('Home Page')
})

// 也可以使用数组的形式绑定两个中间件
app.get('/user', [mv1, mv2], (req, res) => {
res.send('Home Page')
})
中间件的注意事项
1
2
3
4
5
1. 一定要在路由之前注册中间件 (看自己需求)
2. 客户端发送过来的请求,可以连续调用多个中间件进行处理
3. 执行完中间件的业务代码之后,不要忘记调用 `next()` 函数 (看自己需求)
4. 为了防止代码逻辑混乱,调用 `next()` 函数后不要再写额外的代码 (看自己需求)
5. 连续调用多个中间件时,多个中间件之间,共享 `req``res` 对象
中间件的分类
1. 应用级别的中间件

通过 app.use() 或 app.METHOD() 函数,绑定到 app 实例上的中间件,叫做应用级别的中间件

2. 路由级别的中间件
  1. 绑定到 express.Router() 实例上的中间件,叫做路由级别的中间件
  2. 用法上和应用级别中间件没有任何区别,只不过,应用级别中间件是绑定到 app 实例上,路由级别中间件绑定到 router 实例上
1
2
3
4
5
6
7
8
9
10
11
var app = express()
var router = express.Router()

// 路由级别的中间件
router.use(function(req,res,next){
console.log('Time:',Data.now())
next()
})


app.use('/',router)
3. 错误级别中间件
  1. 错误级别中间件的作用: 专门用来捕获整个项目中发生的异常错误,从而防止项目异常崩溃的问题
  2. 格式:错误级别中间件的 function 处理函数中,必须是 4 个形参,形参顺序从前到后,分别是(err, req, res, next)
  3. 注意: 错误级别的中间件,必须注册在所有路由之后(因为捕获不到之后出现的异常)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 1. 路由
app.get('/', (req, res) => {
// 1.1 抛出一个自定义的错误
throw new Error('服务器内部发生了错误')

res.send('Home Page.')
})

// 2. 错误级别的中间件
// 注意:错误级别的中间件,必须注册在所有路由之后
app.use((err, req, res, next) => {
// 2.1 在服务器打印错误消息
console.log('发生了错误:' + err.message)

// 2.2 向客户端响应错误相关的内容
res.send(err.message)
})
异常的类别
  • 编译异常(程序运行不了)
  • 运行异常(程序能运行起来)
4.Express内置中间件
  1. express.static 快速托管静态资源的内置中间件,例如: HTML 文件、图片、CSS 样式等(无兼容性)
  2. express.json 解析 JSON 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
  3. express.urlencoded 解析 URL-encoded 格式的请求体数据(有兼容性,仅在 4.16.0+ 版本中可用)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 配置解析 application/json 格式数据的内置中间件
app.use(express.json())
// 配置解析 application/x-www-form-urlencoded 格式数据的内置中间件
app.use(express.urlencoded({extended:false}))

urlencoded 默认为 true
true: 使用第三方包 qs 解析 请求体数据
false: 使用内置模块 querystring 解析 请求体数据
qs 比 querystring 复杂(更强大), 但是内置模块 querystring 已经足够使用了, 所以里面的参数可以省略不写 express.urlencoded()


// 一般挂载到局部上,避免资源浪费

// 在服务器,可以使用 req.body 这个属性,来接收客户端发送过来的请求体数据
// 默认情况下,如果不配置解析表单数据的中间件,则req.body默认等于undefined
5. 第三方的中间件
1
2
npm i body-parser   // (已经内置了)
req.body // 包含了提交数据的键值对在请求的body中
自定义中间件
data事件
如果数据量比较大,无法一次性发送完毕,则客户端会把数据切割后,分批发送到服务器。所以 data 事件可能会触发多次,每一次触发 data 事件时,获取到数据只是完整数据的一部分,需要手动对接收到的数据进行拼接。
1
2
3
4
5
6
7
// 定义变量,用来存储客户端发送过来的请求体数据
let str = '';
// 客户端发送过来新的请求体数据就会触发
req.on('data',(chunk)=>{
// 拼接请求体数据,隐式转换为字符串
str += chunk;
})
end事件
1
2
3
4
5
// 请求体发送完毕后触发
req.on('end',()=>{
// 打印完整的请求体数据
console.log(str)
})
querystring
1
2
3
4
5
// 导入处理 querystring 的 Node.js 内置模块
const qs = require('querystring');

// 调用qs.parse() 方法,把查询字符串解析为对象
const body = qs.parse(str)
cors跨域
1
2
3
npm i cors
const cors = require('cors');
app.use(cors())
try-catch与异步操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// var fs = require('fs');

// fs.writeFile('./xxx/abc.txt','大家早上好!','utf8',function(err){
// if(err){
// console.log('出错了!');
// throw err;
// }
// console.log('ok');
// });

// 异步操作,try-catch 是无法捕获异常的
// 对于异步操作,要通过判断错误号(err.code)来进行出错处理
var fs = require('fs');
try{
fs.writeFile('./xxx/abc.txt','大家早上好!','utf8',function(err){
console.log('ok');
});
}catch(e){
console.log('出错了!'+e)
}
URL模块
1
var url = require('url'); // 
把用户提交的新闻数据保存到data.json文件中
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
// 1. 获取用户get提交过来的新闻数据
// urlObj.query.title
// urlObj.query.url
// urlObj.query.text


// 2. 把用户提交的新闻数据保存data.json文件中
var list = [];
list.push(urlObj.query);

// 把list数组中的数据写入到data.json文件中
fs.writeFile(path.join(__dirname,'data','data.json'),JSON.stringify(list),function(err){
if(err){
throw err;
}

console.log('OK');
// 设置响应报文头,通过响应报文头告诉浏览器,执行一次页面跳转操作
// 3. 跳转到新闻列表页
// 重定向
res.statusCode = 302;
res.statusMessage = 'Found';
res.setHeader('Location','/');

res.end();
)
querystring模块
1
2
3
4
var querystring = require('querystring');

// 把post请求的查询字符串,转换为一个json对象
postBody = querystring.parse(postBody);
underscore.js
1
2
// Underscore是一个JavaScript实用库,提供了一整套函数式编程的实用功能,但是没有扩展任何JavaScript内置对象
npm install underscore
其他
1
2
3
4
5
6
7
8
decodeURI(filename); // 对url百分比解码
modules.paths // 当前文件查找模块的路径
Buffer.from() // 转换为buffer
Buffer.byteLength(str,'utf8'); // 返回这个字符串的字节长度


--save 添加到依赖项
package.json文件中dependencies依赖列表中