node一些代码

node入门这个教程简单却生动有趣,涵盖了服务器端Javascript,函数式编程,阻塞与非阻塞,回调,Listener事件以及内部外部模块等许多内容。跟着这个教程把代码敲打一边,也算做了个简单的node服务器端代码框架,再要加handler就很方便了。

npm install formidable
需要安装第三方模块formidable,编写下面 四个文件

服务器入口文件 index.js

var server = require("./server");
var router = require("./router");
var requestHandlers = require("./requestHandlers");

var handle = {}
handle["/"] = requestHandlers.start;
handle["/start"] = requestHandlers.start;
handle["/upload"] = requestHandlers.upload;
handle["/show"] = requestHandlers.show;

server.start(router.route, handle);

服务器文件 server.js

var http = require("http");
var url = require("url");

function start(route, handle){
	var server = http.createServer(function(request,response){
			var pathname = url.parse(request.url).pathname;
			console.log("Requesti for " + pathname + " received.");
			route(handle, pathname, response, request);
			});

	server.listen(8888);
	console.log("Server has started.");
}

exports.start = start;

路由器 router.js

//
// 路由函数
//
function route(handle, pathname, response, request){
	console.log("Route the request for " + pathname);
	if(typeof handle[pathname] === "function"){
		handle[pathname](response, request);
	} else {
		console.log("no handler set for " + pathname);
		response.writeHead(404, {"Content-Type":"text/plain"});
		response.write("404 not found");
		response.end();
	}
}

exports.route = route;

handler处理器 requestHandlers.js

var querystring = require("querystring"),
    fs = require("fs"),
    formidable = require("formidable");

var url = require("url");

//
// 显示上传表单
//
function start(response, request){
	console.log("Request Handler 'start' was called.");

	var body = '<html>' +
		'<head>' +
		'<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />' +
		'</head>' +
		'<body>' +
		'<form action="/upload" enctype="multipart/form-data" method="post">' +
		'<input type="file" name="upload" />' +
		'<input type="submit" value="Submit text" />' +
		'</form>' +
		'</body>' +
		'</html>';

	response.writeHead(200, {"Content-Type": "text/html"});
	response.write(body);
	response.end();
}

//
// 使用formidable库,设置回调函数
//
function upload(response, request){
	console.log("Request Handler 'upload' was called.");

	var form = new formidable.IncomingForm();
	console.log("start to parse");
	form.parse(request, function(error, fields, files){
			console.log("parsing done");
			fs.renameSync(files.upload.path, "./test.png");
			response.writeHead(200, {"Content-Type":"text/plain"});
			response.write("received image:<br />");
			response.write("<img src='/show' />");
			response.end();
			});
}

//
// 显示上传图片,通过回调函数输出
//
function show(response,request){
	console.log("Request Handler 'show' was called.");
	fs.readFile("./test.png", "binary", function(error, file){
			if(error){
			response.writeHead(500, {"Content-Type":"text/plain"});
			response.write(error + "\n");
			response.end();
			} else {
			response.writeHead(200, {"Content-Type":"image/png"});
			response.write(file, "binary");
			response.end();
			}
			});
}

//
// 导出handlers供router配置使用
//
exports.start = start;
exports.upload = upload;
exports.show = show;

运行方法node index.js,可以看到实现了文件上传展示的功能。

再要实现其它功能只需要添加自定义的handler并注册到路由上即可。

再参考这篇博文介绍加上静态文件服务功能,最后代码如下

配置文件config.js(网站根目录,资源过期时间配置,压缩选项等设置)

//
// 配置过期事件的文件类型
//
exports.Expires = {
	fileMatch : /^(gif|png|jpg|js|css)$/ig,
	maxAge: 60 * 60 * 24
};

//
// 配置需要gzip压缩的文件类型
//
exports.Compress = {
	fileMatch : /^(css|js|html)$/ig
};

//
// 配置目录首页
//
exports.Welcome = {
	file: "index.html"
};

//
// 配置网站根目录
//
exports.Webroot = {
	path: "webroot"
};

mime.js自定义静态文件类型

//
// mime tyoe
//
exports.types = {
	"css": "text/css",
	"gif": "image/gif",
	"html": "text/html",
	"ico": "image/x-icon",
	"jpeg": "image/jpeg",
	"jpg": "image/jpeg",
	"js": "text/javascript",
	"json": "application/json",
	"pdf": "application/pdf",
	"png": "image/png",
	"svg": "image/svg+xml",
	"swf": "application/x-shockwave-flash",
	"tiff": "image/tiff",
	"txt": "text/plain",
	"wav": "audio/x-wav",
	"wma": "audio/x-ms-wma",
	"wmv": "video/x-ms-wmv",
	"xml": "text/xml"
};

router.js修改路由实现静态文件服务器功能

var path = require("path");
var fs = require("fs");
var mime = require("./mime").types;
var config = require("./config");
var zlib = require("zlib");
//
// router
//
function route(handle, pathname, response, request){
	console.log("Route the request for " + pathname);

	var realpath = config.Webroot.path + pathname;
	
	fs.stat(realpath, function(err, stat){
			//
			// Handlers
			//
			if(err)
			{
				if(typeof handle[pathname] === "function"){
					handle[pathname](response, request);
				}
				// file not exists
				else {
					response.writeHead(404, {"Content-Type":"text/plain"});
					response.write("404 not found");
					response.end();
				}
				return;
			}
			//
			// change /dir to /dir/index.html
			//
			if(stat.isDirectory()) {
				realpath = path.join(realpath, "/", config.Welcome.file);
			}
			//
			// exists Files
			//
			fs.exists(realpath, function(exists){
				if(!exists) {
					response.writeHead(404, {"Content-Type":"text/plain"});
					response.write("404 not found");
					response.end();
					return;
				}
			
				//
				// set last-modified
				//
				var lastModified = stat.mtime.toUTCString();
				response.setHeader("Last-Modified", lastModified);

				if(request.headers["if-modified-since"] && lastModified == request.headers["if-modified-since"]) {
				response.writeHead(304, "Not Modified");	
				response.end();
				return;
				}

				var ext = path.extname(realpath);
				ext = ext ? ext.slice(1) : 'unknown';

				//
				// set content-type
				//
				var contentType = mime[ext] || "text/plain";
				response.setHeader("Content-Type", contentType);

				//
				// set expire time
				//
				if(ext.match(config.Expires.fileMatch)) {
					var expires = new Date();
					expires.setTime(expires.getTime() +
							config.Expires.maxAge * 1000);
					response.setHeader("Expires", 
							expires.toUTCString());
					response.setHeader("Cach-Control", 
							"max-age=" + config.Expires.maxAge);
				}

				var raw = fs.createReadStream(realpath);
				var acceptEncoding = request.headers['accept-encoding'] || "";
				var match = ext.match(config.Compress.fileMatch);
				//
				// compress and echo
				//
				if(match && acceptEncoding.match(/\bgzip\b/)){
					response.writeHead(200,
							{"Content-Encoding":"gzip"}
							);
					raw.pipe(zlib.createGzip()).pipe(response);
				} else if(match && acceptEncoding.match(/\bdeflate\b/)){
					response.writeHead(200,
							{"Content-Encoding":"deflate"}
							);
					raw.pipe(zlib.createDeflate()).pipe(response);
				} else {
					response.writeHead(200, "Ok");
					raw.pipe(response);
				}
			});
	});
}

exports.route = route;

经过上面的修改,不但能自定义handle处理请求,也能支持静态文件(html,css,图片等),其中静态文件全部放在webroot目录下。当然最好还是使用现成的express框架。

猜你喜欢

转载自blog.csdn.net/ciaos/article/details/8451910