首页 > 代码库 > 构建web应用

构建web应用

一、web服务器示例
var http = require(‘http‘);http.createServer(function(req, res){    res.writeHeader(200, {Content-Type : ‘text/plain‘});    res.end(‘hello world!‘);}).listen(80);
二、web应用中常见需求:
(1)解析请求方法(POST GET)
(2)解析路径
(3)解析查询字符串
(4)解析cookie
(5)Basic认证
(6)解析表单数据
(7)文件上传
 
三、解析请求方法
function(req, res){    var method = req.method;    if(method === ‘POST‘){    }else if(method === ‘GET‘){    }else if(method === ‘DELETE‘){    }else if(method === ‘PUT‘){    }else{    }}
四、解析路径
(1)返回静态资源
var url = require(‘url‘);var fs = require(‘fs‘);function(req, res){    var pathname = url.parse(req.url).pathname;    fs.readFile(path.join(ROOT, pathname), function(err, file){        if(err){            res.writeHeader(404);            res.end(‘not Found File‘);            return;        }        res.writeHeader(200);        res.end(file);    });}
 
(2)选择控制器:/controller/action/a/b/c
function(req, res){    var pathname = url.parse(req.url).pathname;    var paths = pathname.split(‘/‘);    var contronller = paths[1] || ‘index‘;    var action = paths[2] || ‘index‘;    var args = paths.slice(3);    if(handler[contronller] && handler[contronller][action]){        handler[contronller][action].apply(null, [req, res].concat(args));    }else{        res.writeHeader(500);        res.end(‘找不到响应控制器‘);    }}
四、查询字符串
var url = require(‘url‘);var query = url.parse(req.url, true).query;//{foo : ‘aaa‘, baz : ‘bbb‘}req.query = query;handle(req, res);
五、cookie
function parseCookie(cookie){    var cookies = {};    if(!cookie){        return cookies;    }    var list = cookie.split(‘;‘);    for(var i = 0,len = list.length;i < len;i++){        var pair = list[i].split(‘=‘);        cookies[pair[0].trim()] = pair[1];    }    return cookies;};req.cookies = parseCookie(req.headers.cookie);handle(req, res); function serialize(name, value, options){    var pairs = [name+‘=‘+value];    if(options.expires){        pairs.push(‘Expires=‘+options.expires.toUTCString());    }    if(options.maxAge){        pairs.push(‘Max-Age=‘+options.maxAge);    }    if(options.path){        pairs.push(‘Path=‘+options.path);    }    if(options.domain){        pairs.push(‘Domain=‘+options.domain);    }    if(options.httpOnly){        pairs.push(‘HTTPOnly‘);    }    if(options.secure){        pairs.push(‘Secure‘);    }    return pares.join(‘;‘);} res.writeHeader(‘Set-Cookie‘, serialize({isVisit : 1}));
六、Session
Cookie缺点:
(1)可在前端改变cookie的值(HTTPOnly可限制前端改变cookie),易篡改。
(2)隐私信息无法存cookie
(3)占用网络带宽(每次请求,相关path下的cookie信息都会在请求头中携带,虽然服务端有时候并不需要所有的cookie信息)
基于以上缺点,敏感信息必须从Session获取。
在服务端为Session生成一个键值,将该键值写入Cookie,用户凭借键值获取自己的session 用于解决http协议无状态缺陷,维护用户状态。
 
七、数据上传
var hasBody = function(req){    return ‘transfer-encoding‘ in req.Headers || ‘content-length‘ in req.Headers; } function(req, res){    if(hasBody(req)){        var buffers = [];        req.on(‘data‘, function(chunk){            buffers.push(chunk);        });        req.on(‘end‘, function(){            req.rawBody = Buffer.concat(buffers).toString();            handle(req, res);        });    }else{        handle(req, res);    }};

 

业务中可以判断conten-type 采用不同的方式解析req.rawBody
x-www-form-urlencoded:
req.body = querystring.parse(req.rawBody); var mime = function(req){    return req.headers[‘content-type‘].split(‘;‘)[0] || ‘‘;} var xml2js = require(‘xml2js‘);var handle = function(req, res){    if(mime(req) === ‘application/json‘){        try{            req.body = JSON.parse(req.rowBody);        }catch(){            res.writeHeader(‘400‘);            res.end(‘invalid json‘);            return;        }    }    if(mime(req) === ‘application/xml‘){        xml2js.parseString(req,rawBody, function(err, xml){            if(err){            }else{                req.body = xml;            }        });    }};

 

附件上传:
content-type : multipart/form-data
var formidable = require(‘formidable‘);function(req, res){    if(hasBody(req)){        if(mime(req) === ‘multipart/form-data‘){            var form = new formidable.IncomingForm();            form.parse(req, function(err, fields, files){                req.body = fields;                req.files = files;                handle(req, res);            });        }    }}

 

八、数据上传与安全
在解析表单,JSON和XML的过程中,如果用户提交的数据量较大,不能直接读入内存。避免内存耗尽的情况发生。一般解决这种问题有以下两种方案:
(1)、限制上传内容的大小,超过大小直接返回400状态码
(2)、流式解析,将数据导向磁盘中,Node中只保留文件路径。
如下为Connect中采用的上传数据量的限制方式:
var bytes = 1024; function(req, res){    var received = 0;    var len = req.headers[‘content-length‘]?parseInt(req.headers[‘content-length‘], 10):null;    if(len > bytes){        res.writeHeader(413);        res.end;        return;    }     res.on(‘data‘, function(chunk){        received += chunk.length;        if(received > bytes){            req.destroy();        }    });        handle(req, res);};
 
CSRF 跨站消息伪造
防御方法:服务端生成随机数,将该随机数告知前端,前端在请求中携带该随机数。没有携带制定规则随机数的请求服务端一律不处理。
 
九、附件下载
设置响应头Content-Disposition : attachment;filename="fdfd.txt"