概述
简单的说 Node.js 就是运行在服务端的 JavaScript。
Node.js 是一个基于 Chrome JavaScript 运行时建立的一个平台。
Node.js 是一个事件驱动 I/O 服务端 JavaScript 环境,基于 Google 的 V8 引擎,V8 引擎执行 Javascript 的速度非常快,性能非常好。
安装使用
Node.js 安装包及源码下载地址为:https://nodejs.org/en/download。
历史版本
Node.js 历史版本下载地址:https://nodejs.org/dist/
创建nodejs应用
- 使用require指令来加载和引入模块。eg: var http = require(“http”);
- 创建服务器
var http = require('http');
http.createServer(function (request,response){
//发送HTTP头部
//HTTP状态值:200:OK
//内容类型: text/plain
response.writeHead(200,{'Content-type': 'text/plain'});
//发送响应数据 “Hello world”
response.end('Hello World\n');
}).listen(8888);
//终端打印信息
console.log('Server running at http://127.0.0.1:8888/');
npm使用介绍
NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种:
- 允许用户从NPM服务器下载别人编写的第三方包到本地使用。
- 允许用户从NPM服务器下载并安装别人编写的命令行程序到本地使用。
- 允许用户将自己编写的包或命令行程序上传到NPM服务器供别人使用。
npm常用命令
npm -v
npm install npm -g //-g表示全局安装,不加-g表示本地安装
npm install -g cnpm --registry=https://registry.npmmirror.com
Node.js回调函数
Node.js 异步编程的直接体现就是回调。
异步编程依托于回调来实现,但不能说使用了回调后程序就异步化了。
回调函数在完成任务后就会被调用,Node 使用了大量的回调函数,Node 所有 API 都支持回调函数。
阻塞代码实例
- 创建input.txt
百度地址:www.baidu.com
- 同目录下创建main.js,阻塞读取
var fs = require("fs");
var data = fs.readFileSync('input.txt');
console.log(data.toString());
console.log("程序执行结束!");
- 同目录下创建main1.js,非阻塞读取
var fs = require("fs");
fs.readFile('input.txt',function(err,data){
if(err) return console.error(err);
console.log(data.toString);
});
console.log("程序执行结束!");
Node.js EventEmitter
events 模块只提供了一个对象: events.EventEmitter。EventEmitter 的核心就是事件触发与事件监听器功能的封装。
var events = require('events');
var eventEmitter = new events.EventEmitter();
//监听器1
var listener1 = function listener1(){
console.log('监听器listener1执行。');
}
//监听器2
var listener2 = function listener2(){
console.log('监听器listener2执行。');
}
//绑定connection事件,处理函数为listener
eventEmitter.addListener('connection',listener1); //添加监听器
eventEmitter.addListener('connection',listener2);
var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + "个监听器监听连接事件。");
eventEmitter.emit('connection');
eventEmitter.removeListener('connection',listener1); //移除监听器
console.log("listener1 不再受监听。");
eventEmitter.emit('connection'); //按监听器的顺序执行每个监听器
eventEmitter.removeListener('connection',listener2);
console.log("listener2 不再受监听。");
var eventListeners = eventEmitter.listenerCount('connection');
console.log(eventListeners + "个监听器监听连接事件。");
console.log("程序执行完毕。");
Node.js Buffer(缓冲区)
创建 Buffer 类
Buffer 提供了以下 API 来创建 Buffer 类:
- Buffer.alloc(size[, fill[, encoding]]): 返回一个指定大小的 Buffer 实例,如果没有设置 fill,则默认填满 0
- Buffer.allocUnsafe(size): 返回一个指定大小的 Buffer 实例,但是它不会被初始化,所以它可能包含敏感的数据
- Buffer.allocUnsafeSlow(size)
- Buffer.from(array): 返回一个被 array 的值初始化的新的 Buffer 实例(传入的 array 的元素只能是数字,不然就会自动被 0 覆盖)
- Buffer.from(arrayBuffer[, byteOffset[, length]]): 返回一个新建的与给定的 ArrayBuffer 共享同一内存的 Buffer。
- Buffer.from(buffer): 复制传入的 Buffer 实例的数据,并返回一个新的 Buffer 实例
- Buffer.from(string[, encoding]): 返回一个被 string 的值初始化的新的 Buffer 实例
常用方法
//写入缓存
buf.wirte(string[,offset[,length]][,encoding]) //[]中为可选参数
//从缓冲区读取数据
buf.toString([encoding[,start[,end]]])
//将Buffer转换为JSON对象
but.toJSON()
eg:
const buf = Buffer.from([0x1,0x2,0x3,0x4,0x5]);
const json = JSON.stringify(buf); //将缓存转为字符串
console.log(json);
const copy = JSON.parse(json,(key,value) => {
return value && value.type === 'Buffer' ? Buffer.from(value.data) : value;
});
console.log(copy);
//缓冲区合并
Buffer.concat(list[,totalLength])
eg:
var buffer1 = Buffer.from(('菜鸟教程'));
var buffer2 = Buffer.from(('www.runoob.com'));
var buffer3 = Buffer.contact([buffer1,buffer2]);
console.log("buffer3 内容:"+buffer3.toString());
//拷贝缓冲区
buf.copy(targetBuffer[,targetStart[,sourceStart[,sourceEnd]]])
eg:
var buf1 = Buffer.from('abcdefghijkl');
var buf2 = Buffer.from('RUNOOB');
//将buf2插入到buf1指定位置上
buf2.copy(buf1,2);
console.log(buf1.toString());
//缓冲区裁剪
buf.slice([start[,end]]);
eg:
var buffer1 = Buffer.from('runoob');
var buffer2 = buffer1.splice(0,2);
console.log("buffer2 content:"+buffer2.toString());
//缓冲区长度
buf.length;
eg:
var buffer = Buffer.from('www.runoob.com');
Node.js Stream(流)
从流中读取数据
eg
var fs = require("fs");
var data = '';
//创建可读流
var readerStream = fs.createReadStream('input.txt');
//设置编码为utf8
readerStream.setEncoding('UTF8');
//处理流事件
readerStream.on('data',function(chunk){
data += chunk;
});
readerStream.on('end',function(){
console.log(data);
});
readerStream.on('error',function(err){
console.log(err.stack);
});
console.log("程序执行完毕");
写入流
eg:
var fs = require("fs");
var data = '菜鸟教程官网地址:www.runoob.com';
//创建一个可以写入的流
var writerStream = fs.createWriteStream('output.txt');
//使用utf8编码写入数据
writerStream.write(data,'UTF8');
//标记文件末尾
writerStream.end();
//完成
writerStream.on('finish',function(){
console.log('写入完成。');
})
//出错
writerStream.on('error',function(){
console.log(err.stack);
})
console.log("程序执行完毕!");
管道流
eg:
var fs = require("fs");
//创建一个可读流
var readerStream = fs.createReadStream('input.txt');
//创建一个可写流
var writerStream = fs.createWriterStream('output.txt');
//管道读写操作
readerStream.pipe(writerStream);
console.log("程序执行完毕!");
链式流
eg
var fs = require("fs");
var zlib = require('zlib');
fs.createReadStream('input.txt').pipe(zlib.createGzip()).pipe(fs.createWriteStream('input.txt.gz'));
console.log("文件压缩完成。");
var fs = require("fs");
var zlib = require('zlib');
// 解压 input.txt.gz 文件为 input.txt
fs.createReadStream('input.txt.gz')
.pipe(zlib.createGunzip())
.pipe(fs.createWriteStream('input.txt'));
console.log("文件解压完成。");
Node.js 模块系统
eg:
//hello.js
function Hello() {
var name;
this.setName = function(thyName) {
name = thyName;
};
this.sayHello = function() {
console.log('Hello ' + name);
};
};
module.exports = Hello; //暴漏Hello模块
//useHello.js
var Hello = require('./hello'); //引入hello.js
hello = new Hello(); //创建对象
hello.setName('zhangsan'); //调用方法
hello.sayHello(); //调用方法
Node.js 路由
路由(Routing)是指确定如何响应对特定端点(URL 路径)的 HTTP 请求的过程。
eg:
//server.js
var http = require("http");
var url = require("url");
function start() {
function onRequest(request, response) {
var pathname = url.parse(request.url).pathname;
console.log("Request for " + pathname + " received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
}
exports.start = start;
//router.js
function route(pathname) {
console.log("About to route a request for " + pathname);
}
exports.route = route;
//index.js
var server = require("./server");
var router = require("./router");
server.start(router.route);
Node.js全局对象
它及其所有属性都可以在程序的任何地方访问,即全局变量
__filename //双下划线
__dirname //双下划线
setTimeout(cb,ms)
clearTimeout(t)
setInterval(cb,ms)
console
process
eg:
console.log( __filename );
console.log( __dirname );
function printHello(){
console.log("Hello,World!");
}
//两秒后执行以上函数
setTimeout(printHello,2000);
function printHello1(){
console.log("Hello,World!");
}
var t = setTimeout(printHello,2000);
clearTimeout(t);
function printHello2(){
console.log("Hello,World!");
}
var st = setInterval(printHello,1000);
console.info("程序开始执行:");
var counter = 10;
console.log("计数:%d",counter);
console.time("获取数据");
console.timeEnd('获取数据');
console.info("程序执行完毕。");
clearInterval(st);
process.on('exit',function(code){
//以下代码永远不会执行
setTimeout(function(){
console.log("该代码不会执行");
},0);
console.log('退出码为:',code);
});
console.log("程序执行结束");
//输出当前目录
console.log('当前目录:'+process.cwd());
//输出当前版本
console.log('当前版本:'+process.version);
//输出内存使用情况
console.log(process.memoryUsage());
Node.js 文件系统
异步和同步
Node.js 文件系统(fs 模块)模块中的方法均有异步和同步版本,例如读取文件内容的函数有异步的 fs.readFile() 和同步的 fs.readFileSync()。
input.txt
百度地址:www.baidu.com
文件读取实例
file.js
var fs = require("fs");
//异步读取
fs.readFile('input.txt',function(err,data){
if(err){
return console.error(err);
}
console.log("异步读取:"+data.toString());
})
//同步读取
var data = fs.readFileSync('input.txt');
console.log("同步读取:" + data.toString());
console.log("程序执行完毕。");
打开文件
fs.open(path,flags[,mode],callback)
- path-文件的路径
- flags-文件打开的行为
- mode-设置文件模式(权限),文件创建默认权限为0666(可读,可写)
- callback-回调函数,带有两个参数如:callback(err,fd)
Flag | 描述 |
---|---|
r | 以只读模式打开文件。文件必须存在,不存在会抛出异常 |
r+ | 以读写模式打开文件。文件必须存在 |
rs | 以同步方式只读打开文件。阻塞操作,但在某些系统上可能会提供更好的稳定性 |
rs+ | 以同步方式读写打开文件。阻塞操作,但在某些系统上可能会提供更好的稳定性 |
w | 以只写模式打开文件。如果文件不存在则创建文件,如果文件存在则截断文件 |
wx | 类似于‘w’,但如果路径存在,则失败 |
w+ | 以读写模式打开文件 |
var fs = require("fs");
//异步打开文件
console.log("准备打开文件!");
fs.open('input.txt','r+',function(err,fd){
if(err){
return console.error(err);
}
console.log("文件打开成功!");
})
获取文件信息
fs.stat(path,callback)
var fs = require('fs');
fs.stat('/Users/liuht/code/itbilu/demo/fs.js',function(err,stats){
console.log(stats.isFile());
})
stats类中的方法有:
方法 | 描述 |
---|---|
stats.isFile() | 是文件返回true,否则返回false |
stats.isDirectory() | 目录返回true,否则返回false |
stats.isBlockDevice() | 块设备返回true,否则返回false |
stats.isCharacterDevice() | 字符设备返回true,否则返回false |
stats.isSymbolicLink() | 软链接返回true,否则返回false |
stats.isFIFO() | 是FIFO,返回true,否则返回false |
stats.isSocket() | 是Socket返回true,否则返回false |
写入文件
fs.writeFile(file,data[,options],callback)
- file-文件名或文件描述符
- data-要写入文件的数据,可以是String(字符串)或Buffer(缓冲)对象
- options-该参数是一个对象,包含{encoding,mode,flag}.
- callback-回调函数,回调函数只包含错误参数(err),在写入失败时返回。
var fs = require('fs');
console.log("准备写入文件");
fs.writeFile('input.txt','我是通过fs.writeFile写入文件的内容!',function(err){
if(err){
return console.error(err);
}
console.log("数据写入成功!");
console.log("-----------分割线-----------");
console.log("读取写入的数据!");
fs.readFile('input.txt',function(err,data){
if(err){
return console.error(err);
}
console.log("异步读取文件数据:"+data.toString());
});
});
读取文件
fs.read(fd,buffer,offset,length,position,callback)
- fd-通过fs.open()方法返回的文件描述符
- buffer-数据写入的缓冲区
- offset-缓冲区写入的写入偏移量
- length-要从文件中读取的字节数
- positon-文件读取的起始位置,如果position的值为null,则会从当前文件指针的位置读取
- callback-回调函数,有三个参数err,bytesRead,buffer.err为错误信息,bytesRead读取字节数,buffer缓冲区对象
var fs = require("fs");
var buf = new Buffer.alloc(1024);
console.log("准备打开已存在的文件!")
fs.open('input.txt','r+',function(err,fd){
if(err){
return console.error(err);
}
console.log("文件打开成功!");
console.log("准备读取文件:");
fs.read(fd,buf,0,buf.length,0,function(err,bytes){
if(err){
console.log(err);
}
console.log(bytes + " 字节被读取");
//仅输出读取的字节
if(bytes > 0){
console.log(buf.slice(0,bytes).toString());
}
})
})
关闭文件
fs.close(fd,callback)
- fd-通过fs.open()方法返回的文件描述符
- callback-回调函数,没有参数
fs.close(fd,function(err){
if(err){
console.log()
}
console.log("文件关闭成功")
})
截取文件
fs.ftruncate(fd,len,callback)
- fd-通过fs.open()方法返回的文件描述符
- len-文件内容截取的长度
- callback-回调函数,没有参数
删除文件
fs.unlink(path,callback)
- path-文件路径
- callback-回调函数,没有参数
创建目录
fs.mkdir(path[,options],callback)
- path-文件路径
- options 参数可以是:
- recursive-是否以递归的方式创建目录,默认为false
- mode-设置目录权限,默认为0777.
- callback-回调函数,没有参数
读取目录
fs.readdir(path,callback)
- path-文件路径
- callback-回调函数,回调函数带有两个参数err,files.err为错误信息,files为目录下的文件数组列表
删除目录
fs.rmdir(path,callback)
- path-文件路径
- callback-回调函数,没有参数
Node.js GET/POST请求
获取get请求内容
var http = require('http');
var url = require('url');
var util = require('util');
http.createServer(function(req,res){
res.writeHead(200,{'Content-Type':'text/plain;charset=utf-8'});
//res.end(util.inspect(url.parse(req.url,true)));
var params = url.parse(req.url,true).query;
res.write("网站名:"+params.name);
res.write("\n");
res.write("网站URL:"+params.url);
res.end();
}).listen(3000);
获取post请求
var http = require('http');
var querystring = require('querystring');
//定义一个html模板,当获取不到body和url的是否显示在页面上
var postHTML = '<html><head><meta charset="utf-8"><title>菜鸟教程 Node.js实例</title><head>'+
'<body>'+
'<form method="post">' +
'网站名:<input name="name"><br>' +
'网站URL:<input name="url"><br>' +
'<input type="submit">' +
'</form>' +
'</body></html>';
http.createServer(function(req,res){
var body = "";
req.on('data',function(chunk){
body += chunk;
});
req.on('end',function(){
body = querystring.parse(body);
res.writeHead(200,{'Content-Type':'text/html;charset=utf8'});
if(body.name && body.url){
res.write("网站名:"+body.name);
res.write("<br>");
res.write("网站URL: "+body.url);
}else{
res.write(postHTML);
}
res.end();
});
}).listen(3000);
Node.js Web模块
//service.js
//引入模块
var http = require('http');
var fs = require('fs');
var url = require('url');
//创建服务器
http.createServer(function(request,response){
//解析请求,包括文件名
var pathname = url.parse(request.url).pathname;
//输出请求的文件名
console.log("Request for"+pathname+" received.");
//从文件系统中读取请求的文件内容
fs.readFile(pathname.substr(1),function(err,data){
if(err){
console.log(err);
//HTTP状态码 404:NOT FOUND
response.writeHead(404,{'Content-Type':'text/html'});
}else{
//HTTP状态码 200:成功
response.writeHead(200,{'Content-Type':'text/html'});
//相应文件内容
response.write(data.toString());
}
//发送响应数据
response.end();
});
}).listen(8080);
console.log('Server running at http://127.0.0.1:8080/');
//index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>菜鸟教程(runoob.com)</title>
</head>
<body>
<h1>我的第一个标题</h1>
<p>我的第一个段落。</p>
</body>
</html>
//client.js
var http = require('http');
//用于请求的选项
var options = {
host: 'localhost',
port: '8080',
path: '/index.html'
}
//处理响应的回调函数
var callback = function(response){
//不断更新数据
var body = '';
response.on('data',function(data){
body += data;
});
response.on('end',function(){
console.log(body);
});
}
//向服务端发送请求
var req = http.request(options,callback);
req.end();
Node.js Express框架
安装使用
cnpm install express --save
cnpm install body-parser --save
cnpm install cookie-parser --save
cnpm install multer --save
- express-Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用,和丰富的 HTTP 工具
- body-parser-node.js中间件,用于处理JSON,Raw,Text和URL编码的数据
- cookie-parser-解析Cookie的工具。
- multer-node.js中间件,用于处理enctype="multipart/form-data"的表单数据。
//引入所需模块
var express = require('express');
var app = express();
//返回数据
app.get('/',function(req,res){
res.send('Hello World');
})
//监听8081端口
var server = app.listen(8081,function(){
var host = server.address().address;
var port = server.address().port;
console.log("应用实例,访问地址为http://%s:%s",host,port);
})
路由
var express = require('express');
var app = express();
//主页输出Hello World
app.get('/',function(req,res){
console.log("主页Get请求");
res.send('Hello Get');
})
app.post('/',function(req,res){
console.log("主页Post请求");
res.send('Hello Post');
})
app.get('/del_user',function(req,res){
console.log("/del_user 响应DELETE请求");
res.send('删除页面');
})
app.get('/list_user',function(req,res){
console.log("/list_user Get请求");
res.send('用户列表页面');
})
app.get('/ab*cd',function(req,res){
console.log("/ab*cd Get 请求");
res.send('正则匹配')
})
var server = app.listen(8081,function(){
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为http://%s:%s",host,port)
})
静态文件
app.use('/public',express.static('public'))
var express = require('express');
var app = express();
app.use('/public', express.static('public'));
app.get('/', function (req, res) {
res.send('Hello World');
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)
})
GET方法
var express = require('express');
var app = express();
app.use('/public', express.static('public'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.get('/process_get', function (req, res) {
// 输出 JSON 格式
var response = {
"first_name":req.query.first_name,
"last_name":req.query.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)
})
POST方法
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
// 创建 application/x-www-form-urlencoded 编码解析
var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.use('/public', express.static('public'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.post('/process_post', urlencodedParser, function (req, res) {
// 输出 JSON 格式
var response = {
"first_name":req.body.first_name,
"last_name":req.body.last_name
};
console.log(response);
res.end(JSON.stringify(response));
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)
})
文件上传
var express = require('express');
var app = express();
var fs = require("fs");
var bodyParser = require('body-parser');
var multer = require('multer');
app.use('/public', express.static('public'));
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ dest: '/tmp/'}).array('image'));
app.get('/index.html', function (req, res) {
res.sendFile( __dirname + "/" + "index.html" );
})
app.post('/file_upload', function (req, res) {
console.log(req.files[0]); // 上传的文件信息
var des_file = __dirname + "/" + req.files[0].originalname;
fs.readFile( req.files[0].path, function (err, data) {
fs.writeFile(des_file, data, function (err) {
if( err ){
console.log( err );
}else{
response = {
message:'File uploaded successfully',
filename:req.files[0].originalname
};
}
console.log( response );
res.end( JSON.stringify( response ) );
});
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("应用实例,访问地址为 http://%s:%s", host, port)
})
Cookie管理
// express_cookie.js 文件
var express = require('express')
var cookieParser = require('cookie-parser')
var util = require('util');
var app = express()
app.use(cookieParser())
app.get('/', function(req, res) {
console.log("Cookies: " + util.inspect(req.cookies));
})
app.listen(8081)