node构建Web基础

关于node搭建Web服务器的基础知识,包括请求、响应、REST服务、静态文件服务、以及表单、文件提交等。为后续做基础。

一、HTTP服务器的基础知识

1.node如何呈现请求

node服务器是长期运行的进程,在他的整个生命周期里,会处理很多请求。

1
2
3
4
5
6
7
8
9
10
var http = require('http');
var server = http.createServer(req,res){
//响应数据写到socket中
res.write('hello world');
//需要通过手动end,否则请求会被挂起
res.end();
//or res.end('hello world');
};

2.设置响应头和状态码

1
2
3
4
5
6
7
8
9
var body = 'hello world';
res.setHeader('Content-Length', body.length);
res.setHeader('Content-type', 'text/plain');
//设置状态码
res.statusCode = 302;
res.end(body);

二、构建RESTful Web服务

REST服务四个谓词,覆盖一个操作任务

  • POST 添加
  • GET 获取
  • DELETE 删除
  • PUT 修改

POST请求创建资源

  1. req.method() 查询谓词(请求类型
  2. req.setEncoding(‘utf8’) 设置编码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
var http = require('http');
var items = [];
var server = http.createServer(function (req, res) {
switch (req.method) {
case 'POST':
var item = '';
req.setEncoding('utf8');
req.on('data', function (chunk) {
item += chunk;
});
req.on('end', function() {
items.push(item)
res.end('OK');
});
break;
default:
// statements_def
break;
}
})

GET请求获取资源

在请求为get时讲items写回即可

  • Buffer.byteLength获取字节长度
1
2
3
4
5
6
7
8
9
10
case 'GET':
var body = items.map(function(elem, index) {
return '(' + index + ') ' + elem;
}).join('\n');
//隐含禁用的node块编码,传输的数据更少
//Buffer.byteLength获取字节长度
res.setHeader('Content-Length', Buffer.byteLength(body));
res.setHeader('Content-Type', 'text/plain; charset="utf-8"');
res.end();

DELETE请求删除资源

  • url模块用来url解析
  • url.parse
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
case 'DELETE':
var path = url.parse(req.url).pathname;
var i = parseInt(path.slice(1), 10);
if(isNaN(i)){
res.statusCode = 400;
res.end('参数无效!')
}else if (!items[i]) {
res.statusCode = 404;
res.end('索引不存在!')
}else{
items.splice(i, 1);
res.end('删除成功!')
}
break;

三、提供静态文件服务

  • 创建简单的静态服务器(HTML,CSS,JS
  • pipe()优化数据传输
  • 通过状态码处理用户和文件系统错误

1.创建静态文件服务器

  • __dirname 文件所在路径
  • fs.ReadStream 高层流式硬盘访问
  • stream.pipe() 优化数据传输
  • fs.stat() 调取文件信息,优先错误处理

写文件,可以将读写stream进行链接,req就是一个readStream

1
2
3
4
var readStream = fs.createReadStream('./ora.txt');
var writeStream = fs.createWriteStream('./target.txt');
readStream.pipe(writeStream);

整体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
var server = http.createServer(function (req,res) {
//获取文件访问路径
var url = req.url,
path = _path.join(root, url);
//检查文件是否存在
fs.stat(path, function (err, stat) {
if(err){
if ('ENOENT' == err.code) {
res.statusCode = 400;
res.end('Not found');
}else{
res.statusCode = 500;
res.end('服务器错误')
}
} else {
//使用pipe优化数据传输
var stream = fs.createReadStream(path);
//错误处理
stream.on('error', function(err) {
res.statusCode = 500;
res.end('服务器错误')
});
stream.pipe(res);
}
})
});

四表单接收

  • 处理表单提交
  • formidable 处理上传文件
  • 实时计算上传进度

1.处理表单域

表单提交请求所带Content-Type有两种

  • application/x-www-form-urlencoded 默认
  • multipart/form-data 含有文件或二进制数据

使用querystring模块解析请求

1
2
3
4
5
var qs = require('querystring');
var body = 'item=aaa';
console.log(qs.parse(body));
//=> {item: 'aaa'}

2. formidable处理文件上传

formidable为社区模块,实现以下过程:

1.通过请求头判断是否为文件上传

1
2
3
4
function isFormData (req) {
var type = req.headers['content-type'] || '';
return 0 == type.indexOf('multipart/form-data');
}

2.通过formidable获取文件和fields

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//实例化
var form = formidable.IncomingForm();
//1.使用监听
form.on('field', function(field, value){});
form.on('file', function(name, file){});
form.on('end', function(){});
//2.使用parse
form.parse(req, function (err, fields, files) {
console.log(fields);
console.log(files);
res.end('上传文件成功!');
})

3.输出上传进度

1
2
3
form.on('progress', function(bytesReceives, bytesExpected){
var progress = Math.floor( bytesReceives / bytesExpected 100%);
}

五、HTTPS