四、提供静态文件服务
1、创建一个静态文件服务器
__dirname ,取值是该文件所在咋目录路径。分散在不同目录中的文件可以有不同的值。
/** * 最进本的ReadStream静态文件服务器 */ var http = require('http'); var parse = require('url').parse; var join = require('path').join; var fs = require('fs'); var root = __dirname; var server = http.createServer(function(req,res){ var url = parse(req.url); var path = join(root,url.pathname); //构造绝对路径 var stream = fs.createReadStream(path); //创建fs.ReadStream stream.on('data',function(chunk){ //将文件数据写到响应中 res.write(chunk); }); stream.on('end',function(){ res.end(); }); }); server.listen(3000);
这个文件服务器大体能用,但还有很多细节需要考虑。
管道和水管:
Node中的管道让来自源头(ReadableStream)的数据,流动到目的地(WriteableStream),我们用pipe方法把管道连接起来。
ReadableSteam.pipe(WriteableStream);
读取一个文件(ReadableStream)并把其中的内容写到另一个文件中(WriteableStream)用的就是管道
var readStream = fs.createReadSteam('./original.txt') var writeStream = fs.createwriteStrem('./copy.tet') readStream.pipe(writeStream)
所有ReadableStream都能接入任何一个WriteableStream。比如HTTP请求(req)对象就是ReadableStream.
2、处理服务器错误
在Node中,所有集成了EventEmitter的类都可能发出error时间。
用fs.stat()实现先发制人的错误处理
因为传输的文件是静态的,所以我们可以用stat()系统调用获取文件的相关信息,比如修改时间、字节数等。
/** *检查文件是否存在,并在响应中提供Content-Length */ var server = http.createServer(function(req,res){ var url = parse(req.url); //解析URL以获取路径名 var path = join(root,url.pathname); fs.stat(path,function(err,stat){ //检查文件是否存在 if(err){ if('ENOENT' == err.code){ res.statusCode = 404; res.end('Not Found'); }else{ res.setHeader('Content-Length',stat.size); //用Stat对象的属性设置Content-Length var stream = fs.createReadStream(path); stream.pipe(res); stream.on('error',function(err){ res.statusCode = 500; res.end('Internal Server Error'); }); } } }); });
五、从表单中接受用户输入
1、处理提交的表单域
表单提交请求带的Content-Type值通常有两种
A、application/X-www-form-urlencoded: 这是HTML表单默认值
B、multipart/form-data: 在表单中含有文件或非ASCII或二进制数据使用。
/** * 支持GET和POST的HTTP服务器. */ var http = require('http'); var items = []; var server = http.createServer(function(req,res){ if('/' == req.url){ switch (req.method){ case 'GET': show(res); break; case 'POST': add(req,res); break; default: badRequest(res); } } else{ notFound(res); } }); server.listen(3000); /*待办事项列表页面的表单和事项列表*/ function show(res){ var html = '<html><head><title>TODO LIST</title></head><body>' +'<h1>TODO LIST</h1>' +'<ul>' +items.map(function(item){ return '<li>'+item+'</li>' }).join('') +'</ul>' +'<form method="post" action="/">' +'<p><input type="text" name="item" /></p>' +'<p><input type="submit" value="Add Item" /></p>' +'</form></body></html>'; res.setHeader('Content-Type','text/html'); res.setHeader('Content-Length',Buffer.byteLength(html)); res.end(html); } /*notFound()函数接受响应对象,将状态吗设为404,响应主体设为Not Found*/ function notFound(res){ res.statusCode = 404; res.setHeader('Content-Type','text/plain'); res.end('NOT FOUND'); } /*返回400 Bad Request响应的函数实现起来跟notFound()几乎一样*/ function badRequest(res){ res.statuCode = 400; res.setHeader('Content-Type','text/plain'); res.end('BadRequest'); } /*最后还要实现add()函数,它会接受req和res连个对象*/ var qs = require('querystring'); function add(req,res){ var body=''; req.setEncoding('utf8'); req.on('data',function(chunk){ body += chunk; }); req.on('end',function(){ var obj = qs.parse(body); items.push(obj.item); show(res); }); }