https://www.nodebeginner.org/index-zh-cn.html Node入门:
var http = require("http");
function onRequest(request, response) {
console.log("Request received.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("Hello World");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("Server has started.");
注意:在 onRequest (我们的回调函数)触发的地方,我用 console.log 输出了一段文本。在HTTP服务器开始工作之后,也输出一段文本。 当我们与往常一样,运行它node server.js时,它会马上在命令行上输出“Server has started.”。当我们向服务器发出请求(在浏览器访问http://localhost:8888/),“Request received.”这条消息就会在命令行中出现。
这就是事件驱动的异步服务器端JavaScript和它的回调啦!(请注意,当我们在服务器访问网页时,我们的服务器可能会输出两次“Request received.”。那是因为大部分浏览器都会在你访问 http://localhost:8888/ 时尝试读取 http://localhost:8888/favicon.ico )
当回调启动,我们的 onRequest() 函数被触发的时候,有两个参数被传入: request 和 response 它们是对象,你可以使用它们的方法来处理HTTP请求的细节,并且响应请求(比如向发出请求的浏览器发回一些东西)
所以我们的代码就是:当收到请求时,使用 response.writeHead() 函数发送一个HTTP状态200和HTTP头的内容类型(content-type),使用 response.write() 函数在HTTP相应主体中发送文本“Hello World"。最后,我们调用 response.end() 完成响应。目前来说,我们对请求的细节并不在意,所以我们没有使用 request 对象。
服务端的模块放在哪里?
我们现在就来谈谈怎么把server.js变成一个真正的Node.js模块,使它可以被我们(还没动工)的 index.js 主文件使用。
Node.js中自带了一个叫做“http”的模块,我们在我们的代码中请求它并把返回值赋给一个本地变量 var http = require("http"); ..... http.createServer(...);
把某段代码变成模块意味着我们需要把我们希望提供其功能的部分 导出 到请求这个模块的脚本
目前,我们的HTTP服务器需要导出的功能非常简单,因为请求服务器模块的脚本仅仅是需要启动服务器而已。
我们把我们的服务器脚本放到一个叫做 start 的函数里,然后我们会导出这个函数。
var http = require("http");
function start() {
function onRequest(request, response) {
console.log("Request 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;
这样,我们现在就可以创建我们的主文件 index.js 并在其中启动我们的HTTP了,虽然服务器的代码还在 server.js 中。
index.js:
var server = require("./server");
server.start();
正如你所看到的,我们可以像使用任何其他的内置模块一样使用server模块:请求这个文件并把它指向一个变量,其中已导出的函数就可以被我们使用了
我们现在可以把我们的应用的不同部分放入不同的文件里,并且通过生成模块的方式把它们连接到一起了。
处理不同的HTTP请求在我们的代码中是一个不同的部分,叫做“路由选择”——那么,我们接下来就创造一个叫做 路由 的模块吧。
我们要为路由提供请求的URL和其他需要的GET及POST参数,随后路由需要根据这些数据来执行相应的代码(这里“代码”对应整个应用的第三部分:一系列在接收到请求时真正工作的处理程序)。
我们需要的所有数据都会包含在request对象中,该对象作为onRequest()回调函数的第一个参数传递。但是为了解析这些数据,我们需要额外的Node.JS模块,它们分别是url和querystring模块。
现在我们来给onRequest()函数加上一些逻辑,用来找出浏览器请求的URL路径:
为了使整个过程非阻塞,Node.js会将POST数据拆分成很多小的数据块,然后通过触发特定的事件,将这些小数据块传递给回调函数。这里的特定的事件有data事件(表示新的小数据块到达了)以及end事件(表示所有的数据都已经接收完毕)。
我们需要告诉Node.js当这些事件触发的时候,回调哪些函数。怎么告诉呢? 我们通过在request对象上注册监听器(listener) 来实现。这里的request对象是每次接收到HTTP请求时候,都会把该对象传递给onRequest回调函数。
如下所示:
request.addListener("data", function(chunk) { // called when a new chunk of data was received }); request.addListener("end", function() { // called when all chunks of data have been received });
在我看来,获取所有来自请求的数据,然后将这些数据给应用层处理,应该是HTTP服务器要做的事情。因此,我建议,我们直接在服务器中处理POST数据,然后将最终的数据传递给请求路由和请求处理器,让他们来进行进一步的处理。
因此,实现思路就是: 将data和end事件的回调函数直接放在服务器中,在data事件回调中收集所有的POST数据,当接收到所有数据,触发end事件后,其回调函数调用请求路由,并将数据传递给它,然后,请求路由再将该数据传递给请求处理程序。
本地文件显示在浏览器中:用一个叫fs的模块
添加/showURL的请求处理程序,该处理程序直接硬编码将文件/tmp/test.png内容展示到浏览器中。当然了,首先需要将该图片保存到这个位置才行。
var querystring = require("querystring"),
fs = require("fs");
function start(response, postData) {
console.log("Request handler 'start' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/upload" method="post">'+
'<textarea name="text" rows="20" cols="60"></textarea>'+
'<input type="submit" value="Submit text" />'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response, postData) {
console.log("Request handler 'upload' was called.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("You've sent the text: "+
querystring.parse(postData).text);
response.end();
}
function show(response, postData) {
console.log("Request handler 'show' was called.");
fs.readFile("/tmp/test.png", "binary", function(error, file) {
if(error) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(error + "\n");
response.end();
} else {
response.writeHead(200, {"Content-Type": "image/png"});
response.write(file, "binary");
response.end();
}
});
}
exports.start = start;
exports.upload = upload;
exports.show = show;
querystring = require("querystring"),
fs = require("fs");
function start(response, postData) {
console.log("Request handler 'start' was called.");
var body = '<html>'+
'<head>'+
'<meta http-equiv="Content-Type" '+
'content="text/html; charset=UTF-8" />'+
'</head>'+
'<body>'+
'<form action="/upload" method="post">'+
'<textarea name="text" rows="20" cols="60"></textarea>'+
'<input type="submit" value="Submit text" />'+
'</form>'+
'</body>'+
'</html>';
response.writeHead(200, {"Content-Type": "text/html"});
response.write(body);
response.end();
}
function upload(response, postData) {
console.log("Request handler 'upload' was called.");
response.writeHead(200, {"Content-Type": "text/plain"});
response.write("You've sent the text: "+
querystring.parse(postData).text);
response.end();
}
function show(response, postData) {
console.log("Request handler 'show' was called.");
fs.readFile("/tmp/test.png", "binary", function(error, file) {
if(error) {
response.writeHead(500, {"Content-Type": "text/plain"});
response.write(error + "\n");
response.end();
} else {
response.writeHead(200, {"Content-Type": "image/png"});
response.write(file, "binary");
response.end();
}
});
}
exports.start = start;
exports.upload = upload;
exports.show = show;
我们还需要将这新的请求处理程序,添加到index.js中的路由映射表中:
var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");
var handle = {}
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
handle["/show"] = requestHandlers.show;
server.start(router.route, handle);
server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");
var handle = {}
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
handle["/show"] = requestHandlers.show;
server.start(router.route, handle);
重启服务器之后,通过访问http://localhost:8888/show,就可以看到保存在/tmp/test.png的图片了。
上传文件:
在上述代码中加一个input标签:
var body = '<html>'+
...
'<input type="file" name="upload">'+
...
var body = '<html>'+
...
'<input type="file" name="upload">'+
...
这里有这样一个问题: 我们需要在upload处理程序中对上传的文件进行处理,这样的话,我们就需要将request对象传递给node-formidable的form.parse函数。
但是,我们有的只是response对象和postData数组。看样子,我们只能不得不将request对象从服务器开始一路通过请求路由,再传递给请求处理程序。 或许还有更好的方案,但是,不管怎么说,目前这样做可以满足我们的需求。
到这里,我们可以将postData从服务器以及请求处理程序中移除了 —— 一方面,对于我们处理文件上传来说已经不需要了,另外一方面,它甚至可能会引发这样一个问题: 我们已经“消耗”了request对象中的数据,这意味着,对于form.parse来说,当它想要获取数据的时候就什么也获取不到了。(因为Node.js不会对数据做缓存)
我们从server.js开始 —— 移除对postData的处理以及request.setEncoding (这部分node-formidable自身会处理),转而采用将request对象传递给请求路由的方式:
接下来是 router.js —— 把postData改成request对象:
现在,request对象就可以在我们的upload请求处理程序中使用了。node-formidable会处理将上传的文件保存到本地/tmp目录中,而我们需要做的是确保该文件保存成/tmp/test.png。 没错,我们保持简单,并假设只允许上传PNG图片
这里采用fs.renameSync(path1,path2)来实现。要注意的是,正如其名,该方法是同步执行的, 也就是说,如果该重命名的操作很耗时的话会阻塞
requestHandlers.js所示:
NODE调用shell:
demo.js:
const callfile = require('child_process');
const newpassword = 'newpwd';
callfile.exec('./a.sh one two three',function (err, stdout, stderr) {
console.dir(arguments);
});
a.sh:
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
输出:
{ '0': null,
'1': '第一个参数为:one\n第二个参数为:two\n第三个参数为:three\n',
'2': '' }
监听器的添加:
使用 emitter.emit(eventName[, ...args]) 按照监听器注册的顺序,同步地调用每个注册到名为 eventName 的事件的监听器,并传入提供的参数。如果事件有注册监听返回 true,否则返回 false。
参数说明:
- eventName :事件名称
- args:传递的参数,多个,类型为任意。
var events = require('events');// 引入 events 模块 var emitter = new events.EventEmitter();// 创建 emitter 对象 var callback1 = function(arg1,arg2){//定义一个回调函数 console.log('hello ',arg1,arg2); } var callback2 = function(arg3,arg4){ console.log('world',arg3,arg4); } emitter.on('connection',callback1)//为 connection 事件注册监听器 on=addListener emitter.on('connection',callback2) //默认情况下,事件监听器会按照添加的顺序依次调用。emitter.prependListener() 方法可用于将事件监听器添加到监听器数组的开头 emitter.prependListener('connection',() => console.log('yilianjie2')) //setTimeout(function(){ emitter.emit('connection','12','34');//调用监听器 //},1000) //结果: yilianjie2 hello 12 34 world 12 34
使用 eventEmitter.once(eventName, listener) 可以注册最多可调用一次的监听器。
var events = require('events');// 引入 events 模块
var emitter = new events.EventEmitter();// 创建 emitter 对象
var n=0;
emitter.once('connection',function(){
++n;
console.log('调用第'+n+'次')
})//为 connection 事件注册监听器
emitter.emit('connection');//调用监听器
emitter.emit('connection');
emitter.emit('connection');
结果:调用第一次
emitter.prependOnceListener() 方法可用于将事件监听器添加到监听器数组的开头。用法与我们前面所学的emitter.prependListener() 方法一致,区别在于这个方法注册的监听器最多只能调用一次
监听器的移除:
使用 emitter.removeListener(eventName, listener) 移除监听器。
参数说明:
- eventName 事件名称
- listener 监听器也就是回调函数名称。
var events = require('events');// 引入 events 模块
var emitter = new events.EventEmitter();// 创建 emitter 对象
var callback = function(){ //定义一个回调函数
console.log('syl');
}
emitter.on('connection',callback)//为 connection 事件注册监听器
emitter.removeListener('connection',callback)//为 connection 事件移除监听器
emitter.emit('connection');//调用监听器
结果: 什么都没有
注:removeListener() 最多只会从监听器数组中移除一个监听器。我们可以多次调用 removeListener() 的方式来一个个的移除我们需要移除掉的监听器。
一旦事件被触发,所有绑定到该事件的监听器都会按顺序依次调用。也就是说在事件触发之后、且最后一个监听器执行完成之前,removeListener() 或 removeAllListeners() 不会从 emit() 中移除它们
// 引入 events 模块
var events = require('events');
// 创建 emitter 对象
var emitter = new events.EventEmitter();
//定义回调函数
var callback1 = function() {
console.log('我是1');
emitter.removeListener('connection',callback2);
};
var callback2 = function() {
console.log('我是2');
};
//为 connection 事件注册监听器
emitter.on('connection',callback1);
emitter.on('connection',callback2);
//第一次调用监听器,callback1 移除了监听器 callback2,但它依然会被调用。触发时内部的监听器数组为 [callback1, callback2]
emitter.emit('connection');
//第二次调用监听器,此时 callback2 已经被移除了。内部的监听器数组为 [callback1]
emitter.emit('connection');
结果: 我是1
我是2
我是1
emitter.off(eventName, listener) 是 emitter.removeListener() 的别名。
使用 emitter.removeAllListeners([eventName]) 移除全部监听器或指定的 eventName 事件的监听器。
// 引入 events 模块
var events = require('events');
// 创建 emitter 对象
var emitter = new events.EventEmitter();
//定义回调函数
var callback1 = function() {
console.log('我是1');
};
var callback2 = function() {
console.log('我是2');
};
//为 connection 事件注册监听器
emitter.on('connection',callback1);
emitter.on('connection',callback2);
//移除connection事件的所有监听器
emitter.removeAllListeners('connection');
//调用监听器
emitter.emit('connection');
结果:什么都没有
emitter.setMaxListeners(n)
使用 emitter.setMaxListeners(n) 设置同一事件的监听器最大绑定数。默认情况下,如果为特定事件添加了超过 10 个监听器,则 EventEmitter 会打印一个警告,这有助于我们发现内存泄露。显然实际编码中并不是所有的事件都要限制 10 个监听器。 emitter.setMaxListeners() 方法可以为指定的 EventEmitter 实例修改限制。当值设为 Infinity(或 0)表示不限制监听器的数量。
查看事件绑定的监听器个数:
emitter.listenerCount(eventName)
//引入events模块
var events = require('events');
//创建emitter对象
var emitter = new events.EventEmitter();
//定义回调函数
var callback1 = function(){
console.log('我是callback1');
}
var callback2 = function(){
console.log('我是callback2')
}
//为connection事件注册监听器
emitter.on('connection',callback1);
emitter.on('connection',callback2);
//查看connection事件绑定的监听器个数
var num = emitter.listenerCount('connection');
console.log(num);
结果:2
error事件:
当 EventEmitter 实例出错时,应该触发 'error' 事件。
如果没有为 'error' 事件注册监听器,则当 'error' 事件触发时,会抛出错误、打印堆栈跟踪、并退出 Node.js 进程。
//引入events模块
var events = require('events');
//创建emitter对象
var emitter = new events.EventEmitter();
//设置监听器
emitter.on('error',(err) => {
console.error('错误信息');
})
emitter.emit('error')
结果:错误信息
Node.js http模块:
//引入http模块
var http = require('http');
//创建服务器
http.createServer(function(req,res){
//发送http头部
//http状态值:200 : ok
//内容类型:text/plain
res.writeHead(200,{'Content-Type':'text/plain'});
//发送响应数据 hello
res.end("hello")
}).listen(8080);
//终端打印信息
console.log("server running at http://127.0.0.1:8080/");
response 对象常用的方法有:
- response.writeHead(statusCode[, statusMessage][, headers])。表示向请求发送响应头。
参数说明:
-
statusCode:状态码,是一个 3 位 HTTP 状态码,如 404 表示网页未找到,200 表示正常。
-
statusMessage: 可选地,可以将用户可读的 statusMessage 作为第二个参数。
-
headers:响应头。也就是设置 Content-Type 的值,用于定义网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件。常用值有:(1)text/html:HTML 格式(2)text/plain:纯文本格式(3)application/x-www-form-urlencoded:数据被编码为名称/值对,这是标准的编码格式。
response.writeHead(200,{'Content-Type':'text/plain;charset=UTF-8'});
此方法只能在消息上调用一次,并且必须在调用response.end()之前调用他
-
response.write() 发送一块响应主体,也就是说用来给客户端发送响应数据。可以直接写文本信息,也可以写我们的 html 代码,注意要设置 Content-Type 的值 。write 可以使用多次,但是最后一定要使用 end 来结束响应,否则客户端会一直等待。
-
response.end() 此方法向服务器发出信号,表示已发送所有响应头和主体,该服务器应该视为此消息完成。必须在每个响应上调用方法 response.end()。
Node.js中的fs模块提供了一个api 用于与文件系统进行交互,导入文件系统模块的语法如下:
var fs=require('fs')
异步打开文件(node.js是同步的,所以代码最好是异步,防止服务器停止响应) fs.open(path,flags[,mode],callback);
例子:创建一个input.txt文件,不写任何内容,然后创建file.js文件打开input.txt文件进行读写
// 引入fs模块
var fs = require("fs");
// 异步打开文件
fs.open('input.txt', 'r+', function(err, fd) { //r+ 打开文件用于读取和写入,文件不存在发生异常
if (err) {
return console.error(err);
}
console.log("文件打开成功!");
});
//结果:文件打开成功!
同步打开文件: fs.openSync(path,flags[,mode])//用的极少
关闭文件:
异步关闭文件:fs.close(fd,callback); //fd是通过fs.open()方法返回的文件描述符
例子:新建一个input.txt文件,内容可有可无,新建一个closeFile.js文件:
var fs = require("fs");
fs.open('input.txt','r+',function(err,fd){
if(err){
return console.error(err)
}
console.log("文件打开成功")
//异步关闭文件
fs.close(fd,function(err){
if(err){
console.log(err)
}
console.log("文件关闭成功")
})
})
//结果:文件打开成功 文件关闭成功
fs.read和fs.write读写文件:
异步读取文件:fs.read(fd,buffer,offset,length,position,callback)
fd:通过fs.open()返回的文件描述符
buffer:是数据写入的缓冲区
offset:是缓冲区中开始写入的偏移量,一般是0
length:整数,指定要读取的字节数
position:指定从文件中开始读取的位置,如果position为null,则从当前位置读取数据,并更新文件位置
callback:回调函数,有三个参数err,byteRead,buffer.err是错误信息,byteRead表示读取的字节数,buffer为缓冲区对象
例子:
新建一个input.txt文件,写入 hello wqq 新建一个js文件
var fs = require("fs");
fs.open('input.txt','r+',function(err,fd){
if(err){
return console.error(err)
}
console.log("文件打开成功")
console.log("准备读取文件:")
//创建一个大小为1024字节的缓存区
var buf = Buffer.alloc(1024);
//异步读取文件
fs.read(fd,buf,0,buf.length,0,function(err,bytes,buf){
if(err){
console.log(err)
}
console.log(bytes + "字节被读取");
//仅输出读取的字节
if(bytes>0){
console.log(buf.slice(0,bytes).toString());
}
//异步关闭文件
fs.close(fd,function(err){
if(err){
console.log(err)
}
console.log("文件关闭成功")
})
})
})
//
文件打开成功
准备读取文件:
9字节被读取
hello wqq
文件关闭成功
异步写入文件fs.write(fd,buffer,offset,length,position,callback);
fd:从指定的文件写入数据
buffer:是数据写入的缓冲区
offset:指定要写入的buffer部分
length:一个整数,指定要写入的字节数
position:指定应该写入此数据的文件开头的偏移量,如果typeof position!=='number',则从当前位置写入数据
callback:回调有三个参数(err,bytesWritten,buffer),其中bytesWritten指定从buffer写入的字节数
例子:
var fs = require("fs");
fs.open('input.txt','a',function(err,fd){
if(err){
return console.error(err)
}
console.log("文件打开成功")
console.log("准备写入文件:")
//新写入内容为 hello world
var buf = Buffer.from(new String(' hello world'));
//异步写入文件
fs.write(fd,buf,0,12,0,function(err,bytes,buf){
if(err){
throw err;
}
console.log("写入成功");
//打印出buffer中存入的数据
console.log(bytes+"字节被写入");
console.log(buf.slice(0,bytes).toString())
//异步关闭文件
fs.close(fd,function(err){
if(err){
console.log(err)
}
console.log("文件关闭成功")
})
})
})
//
文件打开成功
准备写入文件:
写入成功
12字节被写入
hello world
文件关闭成功
还有一种语法:fs.write(fd.string[,position[,encoding]],callback);
fd:从指定的文件写入数据
string:写入的数据,如果不是字符串,则该值将被强制转换为字符串
position 指定应该写入此数据的文件开头的偏移量,如果typeof position!=='number' 则从当前位置写入数据
encoding:指定字符串的编码,默认为'utf-8'
callback:回调有三个参数(err,written,string),其中written指定字符串中已写入文件的字节数,写入的字节数与字符串的字符数是不同的
例子:
var fs = require("fs");
fs.open('input.txt','a',function(err,fd){
if(err){
return console.error(err)
}
console.log("文件打开成功")
console.log("准备写入文件:")
//新写入内容为 hello world
var data = " hello world";
//异步写入文件
fs.write(fd,data,0,'utf-8',function(err,bytes,buf){
if(err){
return console.error(err)
}
console.log(bytes+'字节被写入');
console.log(buf)
//异步关闭文件
fs.close(fd,function(err){
if(err){
console.log(err)
}
console.log("文件关闭成功")
})
})
})
//结果:
文件打开成功
准备写入文件:
12字节被写入
hello world
文件关闭成功
readFile读取文件:
异步读取文件:fs.readFile(path,[options],callback);
path:文件名或文件描述符
options:改参数是一个对象,包含{encoding,flag}.encoding默认值为null,flag默认值为'r'
callback:回调函数
例子:
新建一个input.txt文件,内容:
hello wqq
hello world
新建一个readFile.js文件:
var fs = require('fs');
//读取文件
fs.readFile('input.txt','utf-8',function(err,data){
if(err){
throw err;
}
//读取文件成功
//console.log(data.toString()); //没有utf-8参数的情况下,输出的是二进制,需要转化
console.log(data);
})
//结果:
hello wqq
hello world
fs.readFileSync(filename,[options])是readFile的同步方法
writeFile写入文件:
异步写入文件的:
fs.writeFile(file,data,[options],callback);
file:文件名或文件描述符
data:要写入文件的数据,可以是String,或Buffer对象
options:该参数是一个对象,包含{encoding,mode,flag}.encoding的默认值是'utf-8' mode的默认值是0o666,flag默认是'w'
callback:回调函数
例子:
新建一个writeFile.js文件:
var fs = require('fs');
//写入文件内容,如果不存在会创建一个
//写入时先清空文件
fs.writeFile('text.txt','hello wqq',function(err){
if(err){
throw err;
}
console.log('Saved.');
//写入成功后读取测试
fs.readFile('text.txt','utf-8',function(err,data){
if(err){
throw err;
}
console.log(data);
})
})
//
Saved.
hello wqq //不会叠加
可以通过设置flag的值,来改变默认的写入方式,比如设置为'a',追加数据到文件中.
var fs = require('fs');
//写入文件内容,如果不存在会创建一个
//传递了追加参数{'flag':'a'}
fs.writeFile('text.txt',' hello what is your name',{'flag':'a'},function(err){
if(err){
throw err;
}
console.log('Saved.');
//写入成功后读取测试
fs.readFile('text.txt','utf-8',function(err,data){
if(err){
throw err;
}
console.log(data);
})
})
//
Saved.
hello wqqhello what is your name //运行一次会叠加一次
异步追加内容还有一个方法fs.appendFile(),自己了解
异步获取文件信息的格式为:
fs.stat(path,callback);
path:文件路径
callback回调函数,带有两个参数如:(err,stats) stats是fs.Stats对象
如出现错误,则err.code是常见的系统错误之一
不建议在调用fs.open() fs.readFile()或fs.writeFile()之前使用fs.stat()检测文件是否存在,而是,应该直接打开,读取或写入文件,并在文件不可用时处理引发的错误
fs.stat(path)执行后,会将stat类的实例返回给其他回调函数,可以通过stats类中的提供方法判断文件的相关属性,例如判断是否为文件
例子:
var fs=require('fs');
fs.stat('/home/project/fs.js',function(err,stats){
console.log(stats.isFile());
})
//结果:true
截取文件:
fs.ftruncate(fd[,len],callback);
fd:通过fs.open()方法返回的文件描述符
len:文件内容截取的长度,默认为0
callback:除了可能的异常,完成回调没有其他参数
例子
新建test.txt的文件写入:hello wqq,新建ftr.js
var fs=require('fs');
fs.open('test.txt','r+',function(err,fd){
if(err){
return console.error(err);
}
console.log("文件打开成功");
console.log("截取6字节内的文件内容,超出部分将被去除")
//截取文件
var buf=Buffer.alloc(1024);
fs.ftruncate(fd,6,function(err){
if(err){
console.log(err)
}
console.log("文件截取成功")
console.log("读取相同文件")
fs.read(fd,buf,0,buf.length,0,function(err,bytes){
if(err){
console.log(err)
}
//仅输出读取的字节
if(bytes>0){
console.log(buf.slice(0,bytes).toString());
}
//关闭文件
fs.close(fd,function(err){
if(err){
console.log(err);
}
console.log("文件关闭成功")
})
})
})
})
//结果:
文件打开成功
截取6字节内的文件内容,超出部分将被去除
文件截取成功
读取相同文件
hello
文件关闭成功
删除文件:
fs.unlink(path,callback)
path:文件路径
callback:除了可能的异常,完成回调没有其他参数
例子:
var fs=require('fs');
fs.unlink('test.txt',function(err){
if(err){
return console.error(err);
}
console.log("文件删除成功");
})
//结果:文件删除成功
异步修改文件名的语法:fs.rename(oldpath,newpath,callback)
oldpath:原来的文件名字
newpath:新的文件名字
callback:回调函数,除了可能的异常,完成回调没有其他参数
例子:新建一个old.txt rename.js
var fs=require('fs');
//异步修改文件的名字
fs.rename('old.txt','new.txt',function(err){
if(err){
throw err;
}
console.log("重命名完成");
})
//结果:重命名完成
异步新建目录: fs.mkdir(path[,options],callback);
path:文件路径
options:有两个参数,recursive表示是否以递归的方式创建目录,默认为false.mode设置目录权限,windows上不支持
callback:回调函数,除了可能的异常,完成回调没有其他参数
var fs=require('fs');
console.log('创建目录./test');
//异步创建目录
fs.mkdir('./test/',function(err){
if(err){
return console.error(err)
}
console.log("目录创建成功")
})
//结果:
创建目录./test
目录创建成功
异步读取目录: fs.readdir(path[,options],callback);
path:文件路径
options:有两个参数encoding ,withFileTypes .encoding默认值是utf8 withFileTypes默认值是false
callback:回调函数,回调函数带有两个参数err,files,err为错误信息,files为目录下的文件数组列表
例子:
var fs=require('fs');
fs.readdir('./test',function(err,files){
if(err){throw err;}
//files是个数组
//每个元素是此目录下的文件或文件夹的名称
console.log(files);
})
//读取project目录
fs.readdir('../project',function(err,files){
if(err){
throw err;
}
console.log(files)
})
//结果:
[]
[ 'fs.js', 'new.txt', 'test' ]
异步删除目录:fs.rmdir(path,callback)
例子
var fs=require('fs');
//执行前创建一个空的test目录,用我们之前创建好的
console.log("准备删除目录./test")
fs.rmdir('./test',function(err){
if(err){
return console.error(err);
}
})
//结果:
准备删除目录./test
Node.js的web框架,Express:
npm install express
例子:
var express = require('express');
var app = express();
app.get('/',function(req,res){
res.send('Hello world');
});
app.listen(8080,function(){
console.log("服务器启动了")
})
//结果:
服务器启动了
(点击web服务 会出现Hello world)
路由:
用于确定应用程序如何响应客户端请求,包含一个URI(路径)和一个特定的HTTP请求方法(GET,POST)
每个路由可以具有一个或者多个处理程序函数,这些函数在路由匹配时执行
app.method(path,handler)
注:app是express的实例,method是指HTTP请求方法(GET,POST等),path是指服务器上的路径,handle是指路由匹配时执行的函数
var express = require('express');
var app = express();
//GET请求
app.get('/',function(req,res){
console.log("GET请求");
res.end('Hello ,我是GET请求');
});
//POST请求
app.post('/',function(req,res){
console.log("POST请求");
res.end('Hello,我是POST请求')
})
//index响应index页面,我是GET请求
app.get('/index',function(req,res){
console.log("响应index页面GET请求");
res.end('Hello,我是index页面GET请求')
})
//对页面abcd ,abxcd,ab123cd,等响应GET请求
app.get('/ab*cd',function(req,res){
console.log("/ab*cd GET请求");
res.end('Hello,我是正则匹配')
})
app.listen(8080,function(){
console.log("服务器启动了")
})
对比之前用的原生http,少了很多的判断语句,代码量大大减少,express框架对于Node.js就相当于jQuery和js
静态文件:
express提供了内置的中间件express.static来设置静态文件如:图片,css,js,比如:
//我们只有公开了public目录,才可以直接通过/public/xx的方式访问public目录中的资源
app.use('/public/',express.static('./public/'));
例子:新建一个public目录,目录下新建test.txt文件,里面随便写一句话,再在project目录下新建一个testStatic.js文件
var express = require('express');
var app = express();
app.use(express.static('public'));
app.get('/',function(req,res){
res.end('Hello world')
})
app.listen(8080,function(){
console.log("服务器启动了")
})
//web url后面输入test.txt,会显示里面的内容
Express框架处理GET请求和POST请求
GET请求
表单提交案例: 新建一个getTest.html文件 getTest.js文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form action="/get_test" method="GET">
学号:<input type="text" name="stuNum"> <br />
姓名:<input type="text" name="stuNam">
<input type="submit" value="提交">
</form>
</body>
</html>
var express=require('express');
var app = express();
app.get('/',function(req,res){
//传送指定路径的文件 -会自动根据文件extension设定Content-Type
//也可以用前面的art-template模板引擎
res.sendFile(__dirname + "/" +"getTest.html");
})
app.get('/get_test',function(req,res){ //路由
//输出JSON格式
var response={
'studentNumber':req.query.stuNum,
'studentName':req.query.stuNam
};
console.log(response);
//JSON.stringify()方法是将一个js值(对象或者数组)转换成一个JSON字符串
res.end(JSON.stringify(response));
})
app.listen(8080,function(){
console.log("服务器启动了");
})
//
POST请求:
新建一个postTest.html文件 postTest.js文件
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<form action="/post_test" method="POST">
学号:<input type="text" name="stuNum"> <br />
姓名:<input type="text" name="stuNam">
<input type="submit" value="提交">
</form>
</body>
</html>
var express=require('express');
var app = express();
//加载body-parser
var bodyParser = require('body-parser');
//创建application/x-www-form-urlencoded编码解析
var urlencodedParser = bodyParser.urlencoded({extended:false})
app.get('/',function(req,res){
//传送指定路径的文件 -会自动根据文件extension设定Content-Type
//也可以用前面的art-template模板引擎
res.sendFile(__dirname + "/" +"postTest.html");
})
app.post('/post_test',urlencodedParser,function(req,res){ //路由
//输出JSON格式
var response={
'studentNumber':req.body.stuNum,
'studentName':req.body.stuNam
};
console.log(response);
//JSON.stringify()方法是将一个js值(对象或者数组)转换成一个JSON字符串
res.end(JSON.stringify(response));
})
app.listen(8080,function(){
console.log("服务器启动了");
})
创建一个简单的网站的例子:
用express框架改写前面的创建的例子.其中index.html和register.html的代码与前面一致
首先引入art-template模板引擎:
npm install express srt-template express-art-template
在project目录下建一个view目录,在view下面建index.html和register.html页面,新建一个app.js的文件代码:
var express = require('express');
var app = express();
app.engine('html',require('express-art-template'))
app.get('/', function (req, res) {
res.render('index.html');
})
app.get('/register', function (req, res) {
res.render('register.html');
})
app.listen(8080, function () {
console.log("服务器启动了");
});