介绍

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很好的入门书(或者说手册?),代码虽然简单,但却涵盖很多入门的技术点。

Node开发入门的更多相关文章

  1. Node.js开发入门—使用cookie保持登录

    这次来做一个站点登录的小样例,后面会用到. 这个演示样例会用到Cookie.HTML表单.POST数据体(body)解析. 第一个版本号,我们的用户数据就写死在js文件中. 第二个版本号会引入Mong ...

  2. Node.js开发入门—HelloWorld再分析

    在Node.js开发入门(1)我们用http模块实现了一个简单的HelloWorld站点,这次我们再来细致分析下代码.了解很多其它的细节. 先看看http版本号的HelloWorld代码: 代码就是这 ...

  3. 《Node.js入门》CentOS 6.5下Node.js Web开发环境搭建笔记

    近期想尝试一下英特尔的基于WebRTC协同通信开发套件,所以须要在本地搭建Node.js Web的开发測试环境. 这里讲的是CentOS 下的搭建方法.使用Windows的小伙伴请參考: <No ...

  4. Node.js开发入门—使用AngularJS

    做一个Web应用,一般都有前台和后台,Node.js能够实现后台.利用jade模板引擎也能够生成一些简单的前台页面,但要想开发出具有实际意义的现代Web应用.还得搭配一个Web前端框架. Angula ...

  5. HTML5手机APP开发入门(1)

    HTML5手机APP开发入门(1) 开发框架 Ionicframework V2 + Angular 2 具体内容可以参考一下网站 http://ionicframework.net/ http:// ...

  6. Node.js 入门手册:那些最流行的 Web 开发框架

    这篇文章与大家分享最流行的 Node.js Web 开发框架.Node 是一个服务器端 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用程序,编 ...

  7. 【特别推荐】Node.js 入门教程和学习资源汇总

    这篇文章与大家分享一批很有用的 Node.js 入门教程和学习资源.Node 是一个服务器端的 JavaScript 解释器,它将改变服务器应该如何工作的概念.它的目标是帮助程序员构建高度可伸缩的应用 ...

  8. 基于Nodejs生态圈的TypeScript+React开发入门教程

    基于Nodejs生态圈的TypeScript+React开发入门教程   概述 本教程旨在为基于Nodejs npm生态圈的前端程序开发提供入门讲解. Nodejs是什么 Nodejs是一个高性能Ja ...

  9. 【Electron】Electron开发入门

    Electron简介: Electron提供了丰富的本地(操作系统)的API,使你能够使用纯JavaScript来创建桌面应用程序,并且跨平台(win,mac,linux等各种PC端平台).与其它各种 ...

随机推荐

  1. Windows API一日一练(55)FlushFileBuffers和SetFilePointer函数

    在PC硬件体系结构里,速度最快的存储器是CPU里面的寄存器,接着到二级缓存,再到系统RAM内存,最后才到硬盘.因为这种体系结构,就决定了操作系统对文件的操作方式,或者说是最优化的算法.比方操作系统接收 ...

  2. HDU4512:吉哥系列故事——完美队形I(LICS)

    Problem Description 吉哥这几天对队形比较感兴趣. 有一天,有n个人按顺序站在他的面前,他们的身高分别是h[1], h[2] ... h[n],吉哥希望从中挑出一些人,让这些人形成一 ...

  3. 多表关联查询(ORACLE版)

    前言:这几天学习oracle,把自己对于关联查询的理解,记录下.如有错误请指正! 交叉连接: 交欢连接又称为“笛卡儿积连接”,是两个或多个表之间的无条件连接.一个表中所有的记录与其它表的所有的记录进行 ...

  4. List 去处自定义重复对象方法

    list泛型集合去除重复项,对于单一的某个字段非常简单,但是对于一些自定义要求的还需自定义规则.例子代码: /************绑定乘客信息********/ List<RT.Model. ...

  5. HashSet内存泄露

    import java.util.HashSet; import java.util.Set; public class PersonTest { public static void main(St ...

  6. Chapter 7. Dependency Management Basics 依赖管理基础

    This chapter introduces some of the basics of dependency management in Gradle. 7.1. What is dependen ...

  7. UVA 11770 Lighting Away

    RunID User Problem Result Memory Time Language Length Submit Time 2482977 zhyfzy J Accepted 0 KB 138 ...

  8. Entity Framework 重写OnModelCreating,控制生成表名的单复数

    重写OnModelCreating,控制生成表名的单复数 public class MYDbContext : DbContext { public DbSet<User> Users { ...

  9. java socket报文通信(三)java对象和xml格式文件的相互转换

    前两节讲了socket服务端,客户端的建立以及报文的封装.今天就来讲一下java对象和xml格式文件的相互转换. 上一节中我们列举了一个报文格式,其实我们可以理解为其实就是一个字符串.但是我们不可能每 ...

  10. Objective-C学习篇08—NSDictionary与NSSet

    NSDictionary与NSMutableDictionary NSSet与NSMutableSte 字典 字典:字典分为可变字典NSDictionary和不可变字典NSMutableDiction ...