介绍node.js的web应用,主要包括HTTP服务器、Node.js静态资源管理、Node.js的文件处理功能、Cookie和Session的应用、Node.js安全加密,最后介绍Node.js如何与Nginx搭档。
案例:文字直播Web应用
1. 用户: 直播员(登录), 游客。
2. 直播方式:直播员登录后台,输入相应的的直播信息(图片和文字)。
3. 技术统计: 在线实时记录运动员数据。
4. 游客套路: 游客实时进行在线讨论。
5. 微博分享: 游客通过腾讯微博和新浪微博分享直播内容。
1.简单的HTTP服务器
var http = require("http"),
fs = require("fs"),
url = require("url");
/*创建http服务器*/
http.createServer(function (req, res) {
/**胡获取Web客户端请求路径 */
var pathName = url.parse(req.url).pathname;
/**打印客户端请求req对象中的url、method、headers属性 */
console.log("url: ", req.url);
console.log("method: ", req.method);
console.log("headers: ", req.headers);
console.log('pathName',pathName)
/**根据pathName,路由调用不同处理逻辑 */
switch (pathName) {
case "/index": resIndex(res); //响应HTML页面到Web客户端
break;
case "/img": resImage(res); //响应图片数据到Web客户端
break;
default: resDefault(res); //响应文字信息到Web客户端
break;
}
}).listen(3000);
console.log('Server running at http://127.0.0.1:3000/');
function resIndex(res) {
var readPath = __dirname + "/" + url.parse("index.html").pathname;
var indexPage = fs.readFileSync(readPath);
res.writeHead(200, { "Content-Type": "text/html" });
res.end(indexPage);
}
function resImage(res){
var readPath = __dirname + "/" + url.parse("logo.jpg").pathname;
var indexPage = fs.readFileSync(readPath);
res.writeHead(200, { "Content-Type": "image/jpg" });
res.end(indexPage);
}
function resDefault(res){
res.writeHead(404, { "Content-Type": "text/plain" });
res.end('can not find source');
}
运行结果如下图:依次为请求’/’ , ‘/index’ , ‘img’的返回结果
2.路由处理
虽然用switch可以解决路由问题,但是。。如果请求资源非常复杂时,那个代码量可以想象。。简直灾难。所以。。
特定规则请求路径
根据用户请求的url,依据特定的规则得到相应的执行方法。
请求’/index’ => resIndex(req, res)
请求’/img’ => resImg(req, res)var response = ""; var param = pathname.substr(2), //获取客户端请求的url路径,并获取其第一个参数,将其小写转为大写 firstParam = param.substr(1, 1).toUpperCase(); var functionName = 'res' + firstParam + param; response = res; if(pathname == "/") { resDefault(res); } else if (pathname == "/favicon.ico") { return; } else { eval(functionName + '()'); }
注意: 此方法的参数res, req必须设置为全局变量!!!
利用附带参数来实现路由处理
url路径指定需要执行的模块,通过在HTTP的url中携带一个C参数,表示需要调用的模块中的方法名。
如: ‘/image?c=img’ 表示获取index模块中img方法
//client.js var http = require("http"), url = require("url"), querystring = require("querystring"); http.createServer(function(req, res) { var pathname = url.parse(req.url).pathname; if(pathname == '/favicon.ico') { //请求favicon.ico return; } /**根据用户请求的url路径,截取其中的module和controller */ var module = pathname.substr(1), str = url.parse(req.url).query, controller = querystring.parse(str).c, classObj = ""; //应用try catch来require一个模块,并捕获异常 try { classObj = require("./" + module); } catch (err) { console.log("chdir: " + err); } //require 成功时,调用call方法,实现类中的方法调用执行 if(classObj) { classObj.init(req, res); classObj[controller].call(); } else { //调用不存的模块是,默认返回404错误信息 res.writeHead("404", {"Content-Type": "text/plain"}); res.end("can not find source"); } }).listen(3000); console.log('Server running at http://127.0.0.1:3000/'); //index.js var req, res, fs = require("fs"), url = require("url"); /**创建初始变量函数 */ exports.init = function(request, response){ req = request; res = response; } /**创建index首页函数 */ exports.index = function() { var readPath = __dirname + "/" + url.parse("index.html").pathname; var indexPage = fs.readFileSync(readPath); res.writeHead(200, { "Content-Type": "text/html" }); res.end(indexPage); } //image.js var req, res, fs = require("fs"), url = require("url"); /**创建初始变量函数 */ exports.init = function(request, response){ req = request; res = response; } /**创建index首页函数 */ exports.img = function() { var readPath = __dirname + "/" + url.parse("logo.jpg").pathname; var indexPage = fs.readFileSync(readPath); res.writeHead(200, { "Content-Type": "image/jpg" }); res.end(indexPage); }
运行:这个时候路由链接应该为’/index?c=index’ 或 ‘/image?c=img’
3.GET和POST
GET
GET请求:
http://localhost:3000/test?name=zula&book=nodejs
url.parse(req.url).pathname
=> test?name=zulaurl.parse(req.url).query
=> name=zula&book=nodejsquerystring.parse("name=zula&book=nodejs")
=> {name: “zula”, book: “nodejs”}实例
使用http模块创建一个服务器,接收任意的url请求资源,使用GET方法传递参数,输出每次请求的路径名和请求参数的json对象。
//get_method.js var http = require("http"), url = require("url"), querystring = require("querystring"); http.createServer(function(req, res) { var pathname = url.parse(req.url).pathname, //获取请求路径 paramStr = url.parse(req.url).query, //获取url请求参数 param = querystring.parse(paramStr); //将url请求参数转为json对象 if("/favicon.ico" == pathname) { return; } console.log("pathname: ", pathname ); console.log("paramStr: " , paramStr || "no params" ); console.log("param: " , param ); res.writeHead(200, {'Content-type': 'text/plain'}); res.end("success"); }).listen(3000); console.log('Server running at http://127.0.0.1:3000/');
运行结果:
依次为 的运行结果
http://localhost:3000
http://localhost:3000/11
http://localhost:3000/11?name=zula&age=18
POST
post请求一般较为复杂,一般将post数据拆分为很多小的数据块,通过触发特定的事件,将这些小数据块有序传递给回调函数。addListener(“data”)传输开始和addListener(“end”)传输结束。
实例
var http = require("http"); querystring = require("querystring"); var server = http.createServer(function (req,res) { var postData = ""; /*接受客户端post的数据*/ req.addListener("data", function(postDataChunk) { postData += postDataChunk; }) /*数据接收完成后执行匿名回调函数*/ req.addListener("end", function() { var postStr = JSON.stringify(querystring.parse(postData)); res.writeHead(200,{'Content-Type':'text/plain'}); res.end(postStr + "\n" + req.method); }) }).listen(3000,"127.0.0.1"); console.log('Server running at http://127.0.0.1:3000/');
运行结果:
httpParams
var _req, _res, url = require("url"), querystring = require("querystring"); exports.init = function(req, res){ _res = res; _req = req; } /**获取get参数方法 */ exports.GET = function(key) { var paramStr = url.parse(_req.url).query, param = querystring.parse(paramStr); return param[key] || ""; } /**获取post参数方法 */ exports.POST = function(key, callback) { var postData = ""; _req.addListener("data", function(postDataChunk) { postData += postDataChunk; }) _req.addListener("end", function() { var param = querystring.parse(postData); var value = params[key] || ""; callback(value); }) }