node.js介绍
- 简单的说node.js就是运行在服务器端的JavaScript。
- node.js是一个基于Chrome V8引擎的JavaScript运行环境。
- Node.js 使⽤了⼀个事件驱动、⾮阻塞式I/O 的模型,使其轻量⼜⾼效。
- Node.js 的包管理器 npm,是全球最⼤的开源库⽣态系统。 node所有的模块,都可以在npm中找到并下载使⽤。
- Node.js全⾯⽀持ES6。
运行node.js文件
1、在终端里,进入node文件所在的文件夹,使用node+文件名称,即可运行该文件。
2、使用编辑器提供的运行工具执行文件。
设置一个基础的http服务器
一共分三步:
第一步:引入http模块:
var http=require('http');
第二步:创建请求服务:
- 回调函数两个参数:
req:请求对象;
res:响应对象。 - 获取请求路径:req.url
- 向浏览器发送数据:res.write('要发送的数据')
- 断开浏览器和服务器的链接:res.end()
第三步:监听服务器端口:
server.listen(端口号,函数)
具体代码:
//1、引入http模块
var http = require('http');
//2、利用http模块下的方法创建http服务
//该方法的参数是函数类型:当服务器接收到客户端的请求时,就会触发执行该回调函数。
var server = http.createServer(function(req, res) {
// console.log('接收到客户端请求');
/**
* require:请求对象,所有来自客户端 的请求信息全部存放在该对象中
*
* response :响应对象,所有要发送给客户端的数据,必须通过该对象发送
*/
console.log(req.url); //请求的全部路径
console.log(req.method); //请求的方式
//如果用户请求的是主域名,index.html页面,则发送“欢迎来到首页”数据
if (req.url == '/' || req.url == '/index.html') {
res.write('wlg welcome to index page!!!!'); //可以通过write发送json数据{'':''}
//通过end()主动断开与客户端的链接
// res.end();
} else if (req.url == '/second.html') {
res.write('wlg welcome to second page!!!!');
// res.end();
} else {
res.write('wlg 404 error!!!');
// res.end();
}
res.end();
}).listen(8888);
//3、把该服务挂靠在一个指定的端口号中(让服务监听某个端口)
//端口号共有:65536个,一般,在前三千或前两千的端口是系统私有的端口,我们不能占有。可以给第三方使用的端口在3000以后
// server.listen(8888,function(){
console.log('服务器启动完毕');
// })
node文件模块——文件操作
读取文件:fs.readFile(文件路径,编码格式,回调函数)
fs.readFile('./demo.txt', 'utf-8',function (err,data) {
console.log(data);
})
写入文件:fs.writeFile(文件路径,写入内容,操作,回调函数)
fs.writeFile('demo.txt', '我是动态写⼊的', {
flag: 'a' // a表示拼接;w表示覆盖写⼊
}, function (err) {
if (err) {
return console.error(err);
}
console.log("写⼊成功");
});
复制文件:先读取,后写入。
注意:在文件复制时需要用同步操作。
fs.writeFileSync('demo4.txt',
fs.readFileSync('demo1.txt'));
复制一张图片代码:
fs.readFile('./d03.jpg',function(err,data){
if(err){
console.log(err);
}else{
fs.writeFile('./d0301.jpg',data,{
flag:'w'
},function(err){
if(err){
console.log(err);
}else{
console.log('成功');
}
});
node文件模块——文件操作(管道流操作)
以上函数实现文件的复制时是一次性把要复制的内容一次性放在内存中,复制文件过大后,容易导致内存爆仓。
创建文件读取流:fs.createReadStreame(读取文件路径)
创建文件写入流:fs.createWriteStream(写入文件路径)
读取流的data事件:读取流没读取64kb文件时,触发一次该事件。
案例:使用stream实现文件的复制操作:
// 使⽤stream创建读取流,读取⽂件
var rs = fs.createReadStream('demo1.txt');
// 使⽤strean创建写⼊流,写⼊⽂件
var ws = fs.createWriteStream('demo2.txt');
// 读取⽂件时,没读取64k就处打⼀次data事件
rs.on('data',function (chunk) {
ws.write(chunk, function () {
console.log('写⼊完毕');
});
})
这种方法中的写入流和读取流是异步操作的,读写速度不一致时会导致读取的内容长时间在内存中排队写入,内存还可能爆仓。pipe方法是读取一次,写一次,等写完后再读下一次:rs.pipe(ws);
var fs=require('fs');
//管道流速写文件:把文件分割成若干块(每一块大小是64kb),逐块操作这个文件,以达到节约内存的目的
var rs=fs.createReadStream('./data.txt');
//读取流,在每读出64k的数据后,会触发一次data事件,我们可以通过该事件函数拿到读取出来的数据
//创建写入流,用来写入数据
var ws=fs.createWriteStream('./data1.txt');
//事件函数的参数:chunk保存的就是读取流每次读取出来的数据,如果没有指定读取编码,则以默认的buffer的格式读取。
// rs.on('data',function(chunk){
// console.log(chunk.toString());
// //通过写入流的write方法。把要写入的数据通过写入流写入
// ws.write(chunk,function(){
// console.log('写入完毕!');
// });
// });
//读取流下的pipe方法参数是写入流对象,该方法可以把读取流当前读出的64k数据传给写入流,当写入流写入完毕后,在进行后续的读取操作。
rs.pipe(ws);
谁发送的请求,得到的数据就交给谁处理,如果浏览器发送的请求,得到的数据则展示在浏览器上,如果是ajax发送的请求则将数据交给js代码处理
nodejs文件模块——目录操作
- 创建目录:fs.makdir('目录名',设置权限,回调函数)。
权限设置的四个数值:第一位保持0,第二位:文件所有的权限,第三位:组用户的权限,第四位:其他用户的权限。
权限设置的取值:1:执行,2:写,4:读。
fs.mkdir('test',0777,function (err) {
console.log(err);
})
- 读取目录:fs.readdir('目录名',回调函数)
fs.readdir('test', function (err, files) {
if (err) {
console.error(err);
} else {
console.log(files);
}
})
- 查看文件或目录详情:fs.stat('目录名',回调函数)
fs.stat('test/2.txt', function (err, stats) {
if (err) {
console.log(err);
} else {
console.log(stats);
}
})
- 判断文件是否存在:fs.exists(目录名,回调函数)
fs.exists("test", function (bol) {
console.log(bol);
})
- 通过相对路径获取到绝对路径:fs.realpath('相对路径',回调函数)
fs.realpath('test/2.txt', function (err, path) {
console.log(path);
})
- 修改文件名称:fs.rename(原⽂件名,新⽂件名,回调函数)
fs.rename("demo.txt","demo1.txt",function (err) {
console.log(err);
})
singleRouter通过前台传递不同的请求地址,后台响应不同的地址
var http=require('http');
var url=require('url');
var fs=require('fs');
//这种方式只能验证用户请求的是服务器中的文件,如果遇到用户发送ajax请求则这种方法不行。
var server=http.createServer(function(req,res){
//拿到用户的请求路径
var urlObj=url.parse(req.url,true);
var strUrl='.'+urlObj.pathname;
//判断用户请求的文件是否在服务器中存在
var bol=fs.existsSync(strUrl);
if(strUrl=='./'){
bol=false;
}
if(bol){
//服务器向前端发送文件是以管道流的形式发送的,所以先把文件数据通过管道流从磁盘读取出来,然后发送给客户端
var rs=fs.createReadStream(strUrl)
rs.pipe(res);
}else{
//如果不存在,就发送404错误
var rs=fs.createReadStream('./404.html');
res.statusCode=404;
rs.pipe(res);
}
}).listen(8888,function(){
console.log('服务器启动成功!');
});
服务器端接受get和post请求的不同响应
get请求:
var urlObj=url.parse(req.url,true);
if(urlObj.pathname=='/login'){
//当用户请求了登录接口:login时,获取用户传递的参数,验证参数
console.log(urlObj.query);
var userStr=urlObj.query.user;
var passStr=urlObj.query.pass;
//判断用户名和密码是否通过
if(userStr=='123'&&passStr=='321'){
// var rs=fs.createReadStream('./success.html');
// rs.pipe(res);
//后台向前端发送数据,使用管道流的形式发送
//后台向前端响应请求的信息,是通过res这个写入流发送的,不管向前端发送是文件还是数据,最后都是调用写入流对象中的方法发送。
res.write('{"code":1, "des":"登陆成功"}');
res.end();
}
post请求:
var urlObj=url.parse(req.url,true);
if(urlObj.pathname=='/postlogin'){
//因为post发送数据是以管道流的形式发送的,而req是携带了参数 的管道流,req对象本质就是一个读取流,
//从客户端读取数据(res本质是写入流,向客户端斜土数据),所以可以监听req对象下的data事件,通过该事件函数获取到参数。
req.on('data',function(chunk){
//npm init用来初始化package.json指令
//npm install通过package.json安装第三方库
//num install querystring 表示只下载,不托管给package.json
//num install querystring 表示下载模块并托管给package.json
// console.log(chunk.toString());
//把字符串格式的参数转为对象
var obj=qs.parse(chunk.toString());
if(obj.user=='123'&&obj.pass=='321'){
res.write('{"code":1, "des":"登陆成功"}');
res.end();
}else{
res.write({"code":1,"des":"登陆失败!"});
res.end();
}
});
}
Express模块
1、什么是Express?
node的一个第三方模块,功能和http模块相类似,可以用来做web服务器,但是需要手动安装该模块。
2、如何使用express模块?
- 1、引入模块 var express=require('express');
- 2、初始化 var app=express();
- 3、设置路由项目 app.get('接口名',回调函数);
- 4、监听端口号 app.listen(8888,function(){})
3、如何设置express的路由?
- get请求路由设置 app.get('/', function (req, res){})
- post请求路由设置 app.post('/list', function (req, res) {})
- 通⽤的设置⽅式(不区分get或post)
app.all('*', function (req, res) {
res.send('all');
})
4、如何向前端返回数据、页面?
- 向前端返回数据 res.send('all');
- 向前端返回⻚⾯res.sendFile(‘⻚⾯的绝对路径’);
相对路径转绝对路径:var realPath=fs.realpathSync('.'+req.path);
5、如何获取前端发送的参数?
- get数据:获取前端通过get发送的参数:req对象的query属性保存的是对象类型的参数。
console.log(req.query); - post数据:获取前端通过post发送的参数:给req绑定data事件,没发送⼀部分就在该事件函数中接收⼀部分。当发送结束后所拿到的数据就是完整的参数。
var data ='';
// 给req绑定data事件,获取发送过来的数据
req.on('data',function (chunk) {
data += chunk;
});
// 当数据发送完毕后,触发end事件,在这⾥解析参数
req.on('end', function () {
console.log(data.toString());
res.send('success');
});
注:get提交上来的参数直接可以通过对象形式访问,但post提交上来的参数是⼀个字符串,所以需要借助“querystring”的parse⽅法把字符串转换为对象。
html文件引入外部资源,如何为这些资源设置路由?
// 判断:请求的⻚⾯是否存在
var bol = fs.existsSync('.'+req.url);
// 路由
if (bol) {
if (req.url == '/') {
var rs = fs.createReadStream('./index.html');
rs.pipe(res);
} else {
var rs = fs.createReadStream('.'+req.url);
rs.pipe(res);
}
} else {
var rs = fs.createReadStream('./noPages.html');
rs.pipe(res);
}
响应get请求完整代码:
var express=require('express');
var fs=require('fs');
//初始化模块
var app=express();
//设置路由条目
//设置get接口,向前端发送页面
//通过app对象下的get方法,搭建get请求的路由条目
//第一个参数:接口名
//第二个参数:接口被请求时触发的回调函数
//回调函数中的两个参数
//req:请求对象
//res:响应对象
app.get('/login.html',function(req,res){
//找到用户需要的页面。发送给客户端
//因为sendFile方法需要的路径是绝对路径,所以需要转换
var realPath=fs.realpathSync('./login.html');
res.sendFile(realPath);
});
//架设一个数据接口:获取用户喜欢滴的get数据,响应对应的get数据
app.get('/login',function(req,res){
// console.log(req);
//在express框架中,req.query 属性 中保存的就是对象类型的get参数,所以可以直接通过query属性获取提交的数据
if(req.query.user=='123'&&req.query.pass=='321'){
//发送登录成功的json数据
//向前端发送数据,通过res.send()方法发送,参数就是要发送的字符串
res.send('{"code":1,"res":"success"}');
}else{
res.send('{"code":0,"res":"error!!!"}');
}
});
//设置通配路由,把前边路径条目无法匹配的请求,丢进通配路由中处理
app.get('*',function(req,res){
//判断要请求的接口,文件是否存在
var bol=fs.existsSync('.'+req.path);
if(bol){
var realPath=fs.realpathSync('.'+req.path);
res.sendFile(realPath);
console.log(realPath);
}else{
var realPath=fs.realpathSync('./404.html');
res.sendFile(realPath);
console.log('error');
}
});
//监听端口号
app.listen(8888,function(){
console.log('启动成功!');
});
响应post请求完整代码:
var express=require('express');
var fs=require('fs');
var qs=require('querystring');
var app=express();
//通过get接口给用户发送html页面
app.get('/login.html',function(req,res){
var realPath=fs.realpathSync('.'+req.path);
res.sendFile(realPath);
});
//通过post接口,接受前端提交的post参数
app.post('/login',function(req,res){
//以文件流的形式接受提交的数据
var data='';
req.on('data',function(chunk){
// var obj=qs.parse(chunk.toString());
data +=chunk;
console.log('数据读取中');
});
//当文件流读取完毕时,会触发end事件,在end事件中就可以确保数据是完整的
req.on('end',function(){
console.log('数据读取完毕');
console.log(data.toString());
});
});
app.listen(8888,function(){
console.log('启动!!!!!');
});