- npm:NodeJs包管理器
- express:服务器端比较流行的MVC框架,处理服务请求,路由转发,逻辑处理
- http://socket.io:实现服务端和客户端socket通信解决方案
正式开启JavaScript的后端开发之旅。
由于Node.js平台是在后端运行JavaScript代码,所以,必须首先在本机安装Node环境。输入
node -v 验证
输入
node
,此刻你将进入Node.js的交互环境。
在交互环境下,你可以输入任意JavaScript语句,
要退出Node.js环境,连按两次Ctrl+C。
为啥我们需要一个包管理工具呢?因为我们在Node.js上开发时,会用到很多别人写的JavaScript代码。如果我们要使用别人写的某个包,每次都根据名称搜索一下官方网站,下载代码,解压,再使用,非常繁琐。于是一个集中管理的工具应运而生:大家都把自己开发的模块打包后放到npm官网上,如果要使用,直接通过npm安装就可以直接用,不用管代码存在哪,应该从哪下载。
更重要的是,如果我们要使用模块A,而模块A又依赖于模块B,模块B又依赖于模块X和模块Y,npm可以根据依赖关系,把所有依赖的包都下载下来并管理起来。
npm已经在Node.js安装的时候顺带装好了。我们在命令提示符或者终端输入
npm -v
编辑
hello.js
'use strict'; console.log('Hello, world.');
第一行总是写上
'use strict';
是因为我们总是以严格模式运行JavaScript代码,避免各种潜在陷阱。
运行
node hello.js
每个文件都写上
'use strict';
很麻烦。我们可以给Nodejs传递一个参数,让Node直接为所有js文件开启严格模式:
node
--use_strict calc.js
在编写JavaScript代码的时候,完全可以一边在文本编辑器里写代码,一边开一个Node交互式命令窗口,在写代码的过程中,
把部分代码粘到命令行去验证
,事半功倍!前提是得有个27'的超大显示器!
IDE开发调试工具Visual Studio Code
可以跨!平!台!
模块!
一个.js文件就称之为一个模块
相同名字的函数和变量完全可以分别存在不同的模块中,因此,我们自己在编写模块时,不必考虑名字会与其他模块冲突。
模块的名字就是文件名
module.exports = greet;
把函数
greet
作为模块的输出暴露出去,这样其他模块就可以使用
greet
函数了。
'use strict'
;
// 引入hello模块:
var
greet =
require
(
'./hello'
);
var
s =
'Michael'
; greet(s);
// Hello, Michael!
引入的模块作为
变量
保存在
greet
变量中,
那
greet
变量到底是什么东西?
其实变量
greet
就是用
module.exports = greet;
输出的
greet
函数
。
所以,
main.js
就成功地引用了
hello.js
模块中定义的
greet()
函数,接下来就可以直接使用它了。
一个模块想要对外暴露变量(函数也是变量),可以用
module.exports = variable;
,一个模块要引用其他模块暴露的变量,用
var ref = require('module_name');
就拿到了引用模块的变量。
引入的对象具体是什么,取决于引入模块输出的对象。
输出多个
module.exports = {
greet: greet,
hi: hi,
goodbye: goodbye
};
使用
const
hello
=
require
(
'./hello'
);
hello
.greet(s);
hello.goodbye(s);
JavaScript有且仅有一个全局对象,在浏览器中,叫
window
对象。而在Node.js环境中,也有唯一的全局对象,但不叫
window
,而叫
global
这个对象的属性和方法也和浏览器环境的
window
不同。
进入Node.js交互环境,可以直接输入:
>
global
.console
试试
JavaScript程序是由事件驱动执行的单线程模型,Node.js也不例外。Node.js不断执行响应事件的JavaScript函数,直到没有任何响应事件的函数可以执行时,Node.js就退出了。
如果我们响应
exit
事件,就可以在程序即将退出时执行某个回调函数:
// 程序即将退出时的回调函数:
process.on(
'exit'
,
function
(code) { console.log(
'about to exit with code: '
+ code); });
判断JavaScript执行环境
if
(
typeof
(window) ===
'undefined'
) { console.log(
'node.js'
); }
else
{ console.log(
'browser'
); }
文件系统
异步读文件
var
fs =
require
(
'fs'
); fs.readFile(
'sample.txt'
,
'utf-8'
,
function
(err, data) {
if
(err) { console.log(err); }
else
{ console.log(data); } });
当正常读取时,
err
参数为
null
,
data
参数为读取到的String。
当读取发生错误时,
err
参数代表一个错误对象,
data
为
undefined
。
这也是Node.js标准的回调函数:第一个参数代表错误信息,第二个参数代表结果。后面我们还会经常编写这种回调函数。
读取一个图片文件
fs.readFile(
'sample.png'
,
function
(err, data) {
if
(err) { console.log(err); }
else
{ console.log(data); console.log(data.length +
' bytes'
); } });
当读取二进制文件时,不传入文件编码时,回调函数的
data
参数将返回一个
Buffer
对象。在Node.js中,
Buffer
对象就是一个包含零个或任意个字节的数组(注意和Array不同)。
Buffer
对象可以和String作转换,例如,把一个
Buffer
对象转换成String:
// Buffer -> String
var
text = data.toString(
'utf-8'
); console.log(text);
或者把一个String转换成
Buffer
:
// String -> Buffer
var
buf = Buffer.from(text,
'utf-8'
); console.log(buf);
同步读文件
同步读取的函数和异步函数相比,多了一个
Sync
后缀,并且不接收回调函数,函数直接返回结果。
var
data = fs.readFileSync(
'sample.txt'
,
'utf-8'
); console.log(data);
如果同步读取文件发生错误,则需要用
try...catch
捕获该错误:
try
{
var
data = fs.readFileSync(
'sample.txt'
,
'utf-8'
); console.log(data); }
catch
(err) {
// 出错了
}
写文件
fs.writeFile
fs.stat(filepath,
function
(err, stats) {
if
(!err && stats.isFile()) {
// 没有出错并且文件存在:
console.log(
'200 '
+ request.url);
// 发送200响应:
response.writeHead(
200
);
// 将文件流导向response:
fs.createReadStream(filepath).
pipe
(response); }
else
{
// 出错了或者文件不存在:
console.log(
'404 '
+ request.url);
// 发送404响应:
response.writeHead(
404
); response.end(
'404 Not Found'
); } });
由于
response
对象本身是一个
Writable Stream
,直接用
pipe()
方法就实现了自动读取文件内容并输出到HTTP响应。
stream流
在Node.js中,流也是一个对象,我们只需要响应流的事件就可以了:
data
事件表示流的数据已经可以读取了,
end
事件表示这个流已经到末尾了,没有数据可以读取了,
error
事件表示出错了。
// 打开一个流:
var
rs = fs.createReadStream(
'sample.txt'
,
'utf-8'
); rs.on(
'data'
,
function
(chunk) { console.log(
'DATA:'
) console.log(chunk); }); rs.on(
'end'
,
function
() { console.log(
'END'
); }); rs.on(
'error'
,
function
(err) { console.log(
'ERROR: '
+ err); });
要注意,
data
事件可能会有多次,每次传递的
chunk
是流的一部分数据。
就像可以把两个水管串成一个更长的水管一样,两个流也可以串起来。一个
Readable
流和一个
Writable
流串起来后,所有的数据自动从
Readable
流进入
Writable
流,这种操作叫
pipe
。
Node.js中,
Readable
流有一个
pipe()
方法,就是用来干这件事的。
HTTP模块
Node.js开发的目的就是为了用JavaScript编写Web服务器程序。
request
对象封装了HTTP请求,我们调用
request
对象的属性和方法就可以拿到所有HTTP请求的信息;
response
对象封装了HTTP响应,我们操作
response
对象的方法,就可以把HTTP响应返回给浏览器。
用Node.js实现一个HTTP服务器程序非常简单。
'use strict'
;
// 导入http模块:
var
http =
require
(
'http'
);
// 创建http server,并传入回调函数:
var
server = http.createServer(
function
(request, response) {
// 回调函数接收request和response对象,
// 获得HTTP请求的method和url:
console.log(request.method +
': '
+ request.url);
// 将HTTP响应200写入response, 同时设置Content-Type: text/html:
response.
writeHead
(
200
, {
'Content-Type'
:
'text/html'
});
// 将HTTP响应的HTML内容写入response:
response.end(
'<h1>Hello world!</h1>'
); });
// 让服务器监听8080端口:
server.listen(
8080
); console.log(
'Server is running at http://127.0.0.1:8080/'
);
使用node ***.js执行即可
解析URL:
var
url =
require
(
'url'
); console.log(url.parse(
'http://user:pass@host.com:8080/path/to/file?query=string#hash'
));
结果如下:
Url
{
protocol
:
'http:'
, slashes: true, auth:
'user:pass'
, host:
'host.com:8080'
, port:
'8080'
, hostname:
'host.com'
, hash:
'#hash'
, search:
'?query=string'
, query:
'query=string'
, pathname:
'/path/to/
file
'
, path:
'/path/to/file?query=string'
, href:
'http://user:pass@host.com:8080/path/to/file?query=string#hash'
}
处理本地文件目录需要使用Node.js提供的
path
模块
var
path =
require
(
'path'
);
// 解析当前目录:
var
workDir = path.resolve(
'.'
);
// '/Users/michael'
// 组合完整的文件路径:当前目录+'pub'+'index.html':
var
filePath = path.join(workDir,
'pub'
,
'index.html'
);
// '/Users/michael/pub/index.html'
加密和哈希
Nodejs
用C/C++实现
这些算法后,通过cypto这个模块暴露为JavaScript接口,这样用起来方便,运行速度也快。
MD5是一种常用的哈希算法,用于给任意数据一个“签名”。这个签名通常用一个十六进制的字符串表示:
onst
crypto =
require
(
'crypto'
);
const
hash = crypto.createHash(
'md5'
);//也可以用
sha1
// 可任意多次调用update():
hash.update(
'Hello, world!'
); hash.update(
'Hello, nodejs!'
); console.log(hash.digest(
'hex'
));
// 7e1977739c748beac0c0fd14fd26a544
Hmac算法也是一种哈希算法
const
crypto =
require
(
'crypto'
);
const
hmac = crypto.createHmac(
'sha256'
,
'secret-key'
); hmac.update(
'Hello, world!'
); hmac.update(
'Hello, nodejs!'
); console.log(hmac.digest(
'hex'
));
// 80f7e22570...
AES是一种常用的对称加密算法,加解密都用同一个密钥。
加密结果通常有两种表示方法:hex和base64