zoukankan      html  css  js  c++  java
  • Node开发入门

    介绍

    Node.js采用google的V8虚拟机来解释和执行javascript,也就是允许脱离浏览器环境运行javascript代码。

    Hello World

    婴儿说的第一个字一般是“妈”,程序员写的第一行代码肯定是“hello world”。
    创建helloworld.js文件,输入如下代码:

    console.log("Hello world!");
    

    然后使用node来执行:

    node helloworld.js
    

    终端便输出了“Hello world!”

    构建http服务器

    脱离了无聊的hello world,我们再来看看怎么搭建一个网站,搭建网站首先需要构建一个基础的http服务器。
    这里我们要用到http模块,http是node的内置模块,引用也非常简单:

    var http = require("http");
    

    然后我们再新建一个server.js文件,在里面输入:

    var http = require("http");
    http.createServer(function(request, response){
    	response.writeHead(200, {"Content-Type": "text/plain"});
    	response.write("Hello world");
    	response.end();
    }).listen(8080);
    

    输入完成后,首先用node.js执行:

    node server.js
    

    然后打开浏览器,访问http://localhost:8080/, 然后你就能在页面上看到“Hello world”了。
    不是说好脱离hello world了吗,怎么还来?不用急,马上就不是了。

    创建自己的模块

    现在还只是一个基础的http服务器,除了显示一个hello world以外没有任何价值(当然显示hello world也没什么价值),但是当代码量越来越大时,全放在一个文件里会显得很混乱,怎么办呢?

    我们之前已经用过node内置的http模块,那么我们能不能自己创建模块呢?答案是能,不能还说这么多废话干什么。

    打开server.js文件,定义一个start函数,该函数包含http服务器代码,然后再将函数导出:

    var http = require("http");
    
    function start() {
    	function onRequest(request, response){
    		console.log("request received");	
    		response.writeHead(200, {"Content-Type": "text/plain"});
    		response.write("Hi world");	//说过不用hello world
    		response.end();
    	}
    	http.createServer(onRequest).listen(8080);
    	console.log("Server has started");
    }
    
    exports.start = start;
    

    那怎么去调用这个模块呢?和调用node内置模块类似,先新建一个文件index.js,然后输入如下代码:

    var server = require("./server");
    server.start();
    

    这次我们不再运行server.js了,而是运行index.js:

    node index.js
    

    然后再打开浏览器,访问http://localhost:8080/, 这次我们将不会再看见hello world,而是看见hi world。

    路由

    我们在浏览器访问http://localhost:8080/ ,我们将在页面上看见hi world,我们访问http://localhost:8080/sb, 看到的依然是hi world,这是怎么回事呢?怎么让我访问不同的地址进入到不同的页面呢?

    这里我们就需要创建路由,使路由根据请求的不同的url和get及post参数来执行不同的代码。

    先新建一个router.js,添加以下内容:

    function route (pathname){
    	console.log("request for " + pathname);
    };
    
    exports.route = route;
    

    然后修改server.js,给onRequest函数增加一些代码,这里我们需要用到url模块:

    var http = require("http"), url = require("url");
    
    function start(route) {
    	function onRequest(request, response){
    		var pathname = url.parse(request.url).pathname;
    		console.log("request for " + pathname + " received");	
    		
    		route(pathname);
    		
    		response.writeHead(200, {"Content-Type": "text/plain"});
    		response.write("Hi world");	//说过不用hello world
    		response.end();
    	}
    	http.createServer(onRequest).listen(8080);
    	console.log("Server has started");
    }
    
    exports.start = start;
    

    当然,也要修改index.js,将路由函数注入到服务器中:

    var server = require("./server"), router = require("./router");
    server.start(router.route);
    

    这样路由的基本功能就完成了,但是路由貌似还是什么事也没有做。

    给路由增加处理程序

    路由的功能应该是针对不同的url有着不同的处理方式,例如处理http://localhost:8080/ 和处理localhost:8080/sb是不一样的。

    我们再增加一个请求处理的模块,新建requestHandlers.js,定义两个函数,并接受response参数:

    function start(response){
    	response.writeHead(200, {"Content-Type": "text/plain"});
    	response.write("Start!");
    	response.end();
    }
    
    function sb(response) {
    	response.writeHead(200, {"Content-Type": "text/plain"});
    	response.write("Fuck sb!")
    	response.end();
    }
    
    exports.start = start;
    exports.sb = sb;
    

    javascript的对象就是一个键值对的集合,这里的值可以是任何类型,包括函数,我们可以在index.js中这样引入:

    var server = require("./server"), 
    	router = require("./router"), 
    	requestHandlers = require("./requestHandlers");
    
    var handle = {};
    handle["/"] = requestHandlers.start;
    handle["/start"] = requestHandlers.start;
    handle["/sb"] = requestHandlers.sb;
    
    server.start(router.route, handle);
    

    然后修改server.js:

    var http = require("http"), url = require("url");
    
    function start(route, handle) {
    	function onRequest(request, response){
    		var pathname = url.parse(request.url).pathname;
    		console.log("request for " + pathname + " received");	
    		
    		route(handle, pathname, response);
    	}
    	http.createServer(onRequest).listen(8080);
    	console.log("Server has started");
    }
    
    exports.start = start;
    

    相应的修改router.js:

    function route(handle, pathname, response) {
    	console.log("request for " + pathname);
    
    	if (typeof handle[pathname] == "function") {
    		handle[pathname](response);
    	} else {
    		console.log("No request handler found for " + pathname);
    		response.writeHead(404, { "Content-Type": "text/html" });
    		response.write("404 Not found");
    		response.end();
    	}
    };
    
    exports.route = route;
    

    然后我们就可以浏览器中看见不同的url请求进行了不同的处理。
    请求http://localhost:8080/ 和http://localhost:8080/start, 页面则会显示“Start!”。
    请求http://localhost:8080/sb, 页面则显示“Fuck sb!”。
    请求http://localhost:8080/fucksb,页面则显示“404 Not found”。

    处理post请求

    那怎么处理post请求呢?

    我们这次要做的就是在页面显示一个文本框,让用户输入,然后通过post请求提交给服务器,服务器接收到请求并将输入的内容输出到浏览器的页面中。

    首先我们需要修改requestHandlers.js,让页面显示一个文本框,并通过form表单提交给服务器:

    function start(response) {
    	var body = '<html>' +
    		'<head>' +
    		'<meta http-equiv="Content-Type" content="text/html; ' +
    		'charset=UTF-8" />' +
    		'</head>' +
    		'<body>' +
    		'<form action="/sb" method="post">' +
    		'<input type="text" name="text"/>' +
    		'<input type="submit" value="Submit text" />' +
    		'</form>' +
    		'</body>' +
    		'</html>';
    
        response.writeHead(200, { "Content-Type": "text/html" });
        response.write(body);
        response.end();
    }
    
    function sb(response) {
    	response.writeHead(200, { "Content-Type": "text/plain" });
    	response.write("Fuck sb!")
    	response.end();
    }
    
    exports.start = start;
    exports.sb = sb;
    

    当用户提交表单时,就会触发/sb请求处理程序来处理post请求的问题,但是如果用户提交的数据很大甚至是一个文件,这种大数据量的请求必然会导致用户操作的阻塞,因此我们需要采用异步回调的方式来处理数据。

    我们需要在request对象上注册监听(listener)。
    继续修改server.js:

    var http = require("http"), url = require("url");
    
    function start(route, handle) {
    	function onRequest(request, response) {
    		var postData = "";
    		var pathname = url.parse(request.url).pathname;
    		console.log("request for " + pathname + " received");
    
    		request.setEncoding("utf8");
    		request.addListener("data", function (postDataChunk) {
    			postData += postDataChunk;
    		});
    
    		request.addListener("end", function () {
    			route(handle, pathname, response, postData);
    		})
    	}
    	http.createServer(onRequest).listen(8080);
    	console.log("Server has started");
    }
    
    exports.start = start;
    

    因为增加了post提交来的参数,因此我们需要修改router.js,将postData传递给处理程序:

    function route(handle, pathname, response, postData) {
    	console.log("request for " + pathname);
    
    	if (typeof handle[pathname] === "function") {
    		handle[pathname](response, postData);
    	} else {
    		console.log("No request handler found for " + pathname);
    		response.writeHead(404, { "Content-Type": "text/plain" });
    		response.write("404 Not found");
    		response.end();
    	}
    };
    
    exports.route = route;
    

    然后修改requestHandlers.js的sb函数,接收参数并将数据输出:

    function start(response) {
    	var body = '<html>' +
    		'<head>' +
    		'<meta http-equiv="Content-Type" content="text/html; ' +
    		'charset=UTF-8" />' +
    		'</head>' +
    		'<body>' +
    		'<form action="/sb" method="post">' +
    		'<input type="text" name="text"/>' +
    		'<input type="submit" value="Submit text" />' +
    		'</form>' +
    		'</body>' +
    		'</html>';
    
        response.writeHead(200, { "Content-Type": "text/html" });
        response.write(body);
        response.end();
    }
    
    function sb(response, postData) {
    	response.writeHead(200, { "Content-Type": "text/plain" });
    	response.write(postData);
    	response.end();
    }
    
    exports.start = start;
    exports.sb = sb;
    

    然后重新执行

    node index.js
    

    打开浏览器访问http://localhost:8080/, 并在文本框中输入“sb”,点击提交,就会跳转到/sb页面,显示“text=sb”。

    好像混进了奇怪的东西,我明明输入的sb,显示的为什么会是“text=sb”?

    这是因为点击submit后,将整个form表单信息都提交过去了(如果form中还有其他内容也会一并提交),这里我们只关心文本框中的text信息,可以使用querystring模块来处理:

    var text = querystring.parse(postData).text;
    

    完整代码如下:

    var querystring = require("querystring");
    
    function start(response) {
    	var body = '<html>' +
    		'<head>' +
    		'<meta http-equiv="Content-Type" content="text/html; ' +
    		'charset=UTF-8" />' +
    		'</head>' +
    		'<body>' +
    		'<form action="/sb" method="post">' +
    		'<input type="text" name="text"/>' +
    		'<input type="submit" value="Submit text" />' +
    		'</form>' +
    		'</body>' +
    		'</html>';
    
        response.writeHead(200, { "Content-Type": "text/html" });
        response.write(body);
        response.end();
    }
    
    function sb(response, postData) {
    	response.writeHead(200, { "Content-Type": "text/plain" });
    	response.write(querystring.parse(postData).text);
    	response.end();
    }
    
    exports.start = start;
    exports.sb = sb;
    

    一个简单的http服务器就构建完毕了。

    结语

    本文参考The Node Beginner Book,算是这本书的阉割版吧。这本书是node很好的入门书(或者说手册?),代码虽然简单,但却涵盖很多入门的技术点。

  • 相关阅读:
    PHP $_SERVER变量
    Buddy system伙伴分配器实现
    Linux iconv使用
    内存管理(memory allocation内存分配)
    内存碎片
    《STL源码剖析》chapter2空间配置器allocator
    Effective C++学习笔记:初始化列表中成员列出的顺序和它们在类中声明的顺序相同
    c++ explicit
    《STL源码剖析》环境配置
    C++ STL的各种实现版本
  • 原文地址:https://www.cnblogs.com/Shoring/p/4741362.html
Copyright © 2011-2022 走看看