构建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"
 

构建web应用,古老的榕树,5-wow.com

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。