Node.js实战 建立简单的Web服务器


Posted in Javascript onMarch 08, 2012

前面一章,我们介绍了Node.js这个面向互联网服务的JavaScript服务器平台,同时Node.js的运行环境已经搭建起来,并通过两段HelloWorld程序验证了Node.js的基本功能。本章我们同样通过实战的演练,利用Node.js建立一个简单的Web服务器。

Node.js实战 建立简单的Web服务器

    如果你熟悉.NET或其他类似平台的Web开发,你可能会像,建立一个Web服务器有什么,在Visual Studio中建立一个Web工程,点击运行即可。事实的确是这样,但请不要忘记,这样的代价是,比如果说,你是用.NET开发Web应用,你就使用了完整的IIS作为你的Web服务器基础,这样当你的应用发布时就只能用IIS了。而如果使用独立服务器(利用System.Web.Hosting自己构建的话),你则必须处理各种HttpListener和相应线程,则会比较麻烦,毕竟.NET不是专注于面向Web的。Node.js在这方面提供了方便且可定制的途径,你可以在其基础上构建精巧且完全面向你应用的服务平台。

一、建立简单的Web服务器涉及到Node.js的一些基本知识点:

1、请求模块
在Node.js中,系统提供了许多有用的模块(当然你也可以用JavaScript编写自己的模块,以后的章节我们将详细讲解),如http、url等。模块封装特定的功能,提供相应的方法或属性,要使用这些模块,需要先请求模块获得其操作对象。

例如要使用系统的http模块,可以这样写:

var libHttp = require('http'); //请求HTTP协议模块

这样,以后的程序将可以通过变量libHttp访问http模块的功能。本章例程中使用了以下系统模块:
http:封装http协议的服务器和客户端实现;
url:封装对url的解析和处理;
fs:封装对文件系统操作的功能;
path:封装对路径的解析功能。
有了这些模块,我们就可以站在巨人的肩膀上构建自己的应用。
2、控制台
为了更好的观察程序的运行,方便在异常时查看错误,可以通便变量console使用控制台的功能。
console.log('这是一段日志信息'); 
计时并在控制台上输出计时信息: 
//开始计时 
console.timeEnd('计时器1'); //开始名称为“计时器1”的计时器 
... 
... 
... 
//结束计时,并输出到控制台 
console.timeEnd('计时器1'); //结束称为“计时器1”的计时器并输出

3、定义函数
在Node.js中定义函数的办法与普通JavaScript中完全相同,不过我们推荐的写法如下,即使用一个变量为函数命名,这样可以比较方便明确的将函数作为参数传递给其他函数:
//定义一个名为showErr的函数 
var showErr=function(msg){ 
var inf="错误!"+msg; 
console.log(inf+msg); 
return msg; 
}

4、创建Web服务器并侦听访问请求
创建Web服务器最重要的是提供Web请求的响应函数,它有两个参数,第一个代表客户端请求的信息,另一个代表将要返回给客户端的信息。在响应函数中应解析请求信息,依据请求,组装返后内容。
//请求模块 
var libHttp = require('http'); //HTTP协议模块 
//Web服务器主函数,解析请求,返回Web内容 
var funWebSvr = function (req, res){ 
res.writeHead(200, {'Content-Type': 'text/html'}); 
res.write('<html><body>'); 
res.write('<h1>*** Node.js ***</h1>'); 
res.write('<h2>Hello!</h2>'); 
res.end('</body></html>'); 
} 
//创建一个http服务器 
var webSvr=libHttp.createServer(funWebSvr); 
//开始侦听8124端口 
webSvr.listen(8124);

5、解析Web请求
对于简单的Web网页访问请求,重要的信息包含在请求信息参数的url里,我们可以使用url解析模块解析url中的访问路径,并利用path模块,将访问路径组装为要访问的实际文件路径用于返回。
var reqUrl=req.url; //获取请求的url 
//向控制台输出请求的路径 
console.log(reqUrl); 
//使用url解析模块获取url中的路径名 
var pathName = libUrl.parse(reqUrl).pathname; 
//使用path模块获取路径名中的扩展名 
if (libPath.extname(pathName)=="") { 
//如果路径没有扩展名 
pathName+="/"; //指定访问目录 
} 
if (pathName.charAt(pathName.length-1)=="/"){ 
//如果访问目录 
pathName+="index.html"; //指定为默认网页 
} 
//使用路径解析模块,组装实际文件路径 
var filePath = libPath.join("./WebRoot",pathName);

6、设置返回头
由于是Web请求,需要在返回内容中包含http返回头,这里重点是依据要访问的文件路径的文件扩展名,设置http返回头的内容类型。
var contentType=""; 
//使用路径解析模块获取文件扩展名 
var ext=libPath.extname(filePath); 
switch(ext){ 
case ".html": 
contentType= "text/html"; 
break; 
case ".js": 
contentType="text/javascript"; 
break; 
... 
... 
default: 
contentType="application/octet-stream"; 
} 
//在返回头中写入内容类型 
res.writeHead(200, {"Content-Type": contentType });

7、向返回对象中写入访问的文件内容
有了需要访问的文件实际路径,有了文件对应的内容类型,就可以利用fs文件系统模块读取文件流并返回给客户端。
//判断文件是否存在 
libPath.exists(filePath,function(exists){ 
if(exists){//文件存在 
//在返回头中写入内容类型 
res.writeHead(200, {"Content-Type": funGetContentType(filePath) }); 
//创建只读流用于返回 
var stream = libFs.createReadStream(filePath, {flags : "r", encoding : null}); 
//指定如果流读取错误,返回404错误 
stream.on("error", function() { 
res.writeHead(404); 
res.end("<h1>404 Read Error</h1>"); 
}); 
//连接文件流和http返回流的管道,用于返回实际Web内容 
stream.pipe(res); 
} 
else { //文件不存在 
//返回404错误 
res.writeHead(404, {"Content-Type": "text/html"}); 
res.end("<h1>404 Not Found</h1>"); 
} 
});

二、测试及运行
1、完整源码
以下100行左右的JavaScript就是建立这样一个简单web服务器的全部源码:
//------------------------------------------------ 
//WebSvr.js 
// 一个演示Web服务器 
//------------------------------------------------ 
//开始服务启动计时器 
console.time('[WebSvr][Start]'); 
//请求模块 
var libHttp = require('http'); //HTTP协议模块 
var libUrl=require('url'); //URL解析模块 
var libFs = require("fs"); //文件系统模块 
var libPath = require("path"); //路径解析模块 
//依据路径获取返回内容类型字符串,用于http返回头 
var funGetContentType=function(filePath){ 
var contentType=""; 
//使用路径解析模块获取文件扩展名 
var ext=libPath.extname(filePath); 
switch(ext){ 
case ".html": 
contentType= "text/html"; 
break; 
case ".js": 
contentType="text/javascript"; 
break; 
case ".css": 
contentType="text/css"; 
break; 
case ".gif": 
contentType="image/gif"; 
break; 
case ".jpg": 
contentType="image/jpeg"; 
break; 
case ".png": 
contentType="image/png"; 
break; 
case ".ico": 
contentType="image/icon"; 
break; 
default: 
contentType="application/octet-stream"; 
} 
return contentType; //返回内容类型字符串 
} 
//Web服务器主函数,解析请求,返回Web内容 
var funWebSvr = function (req, res){ 
var reqUrl=req.url; //获取请求的url 
//向控制台输出请求的路径 
console.log(reqUrl); 
//使用url解析模块获取url中的路径名 
var pathName = libUrl.parse(reqUrl).pathname; 
if (libPath.extname(pathName)=="") { 
//如果路径没有扩展名 
pathName+="/"; //指定访问目录 
} 
if (pathName.charAt(pathName.length-1)=="/"){ 
//如果访问目录 
pathName+="index.html"; //指定为默认网页 
} 
//使用路径解析模块,组装实际文件路径 
var filePath = libPath.join("./WebRoot",pathName); 
//判断文件是否存在 
libPath.exists(filePath,function(exists){ 
if(exists){//文件存在 
//在返回头中写入内容类型 
res.writeHead(200, {"Content-Type": funGetContentType(filePath) }); 
//创建只读流用于返回 
var stream = libFs.createReadStream(filePath, {flags : "r", encoding : null}); 
//指定如果流读取错误,返回404错误 
stream.on("error", function() { 
res.writeHead(404); 
res.end("<h1>404 Read Error</h1>"); 
}); 
//连接文件流和http返回流的管道,用于返回实际Web内容 
stream.pipe(res); 
} 
else { //文件不存在 
//返回404错误 
res.writeHead(404, {"Content-Type": "text/html"}); 
res.end("<h1>404 Not Found</h1>"); 
} 
}); 
} 
//创建一个http服务器 
var webSvr=libHttp.createServer(funWebSvr); 
//指定服务器错误事件响应 
webSvr.on("error", function(error) { 
console.log(error); //在控制台中输出错误信息 
}); 
//开始侦听8124端口 
webSvr.listen(8124,function(){ 
//向控制台输出服务启动的信息 
console.log('[WebSvr][Start] running at http://127.0.0.1:8124/'); 
//结束服务启动计时器并输出 
console.timeEnd('[WebSvr][Start]'); 
});

2、资源目录

    既然要建立Web服务器,我们需要创建一个WebRoot目录来存放实际的网页和图片资源,“WebRoot”的目录名在以上源码中被用于组装实际文件路径。

Node.js实战 建立简单的Web服务器

 

3、运行并测试

    在命令行中输入:

node.exe WebSvr.js

   我们的Web服务器就运行起来了,这时,可以通过浏览器对其进行访问,运行效果如下:

Node.js实战 建立简单的Web服务器

 

 后记

    利用Node.js我们可以方便建立相对独立的Web服务器,其事件驱动的特性避免繁琐的线程保护,其基础模块更降低了开发难度。本章建立的Web服务器只是一个简单的样本,没有过多的考虑模块化、安全性等问题,但可以从中掌握Node.js开发的一些基本的知识。
作者:汪峰 www.otlive.cn

Javascript 相关文章推荐
javascript 冒泡排序 正序和倒序实现代码
Dec 14 Javascript
如何将JS的变量值传递给ASP变量
Dec 10 Javascript
Jquery 返回json数据在IE浏览器中提示下载的问题
May 18 Javascript
jQuery html()方法使用不了无法显示内容的问题
Aug 06 Javascript
jquery ztree异步搜索(搜叶子)实践
Feb 25 Javascript
谈一谈js中的执行环境及作用域
Mar 30 Javascript
bootstrap paginator分页前后台用法示例
Jun 17 Javascript
用js屏蔽被http劫持的浮动广告实现方法
Aug 10 Javascript
vue使用v-for实现hover点击效果
Sep 29 Javascript
Vue官方推荐AJAX组件axios.js使用方法详解与API
Oct 09 Javascript
详解可以用在VS Code中的正则表达式小技巧
May 14 Javascript
解决vue使用vant轮播组件swipe + flex时文字抖动问题
Jan 07 Vue.js
使用UglifyJS合并/压缩JavaScript的方法
Mar 07 #Javascript
Uglifyjs(JS代码优化工具)入门 安装使用
Apr 13 #Javascript
node.js 一个简单的页面输出实现代码
Mar 07 #Javascript
服务器端的JavaScript脚本 Node.js 使用入门
Mar 07 #Javascript
JavaScript高级程序设计 读书笔记之十一 内置对象Global
Mar 07 #Javascript
拥抱模块化的JavaScript
Mar 07 #Javascript
那些年,我还在学习jquery 学习笔记
Mar 05 #Javascript
You might like
《星际争霸2》终章已出 RTS时代宣告终结
2017/02/07 星际争霸
再说下636单管机
2021/03/02 无线电
PHP开启opcache提升代码性能
2015/04/26 PHP
ThinkPHP自定义函数解决模板标签加减运算的方法
2015/07/03 PHP
用js 让图片在 div或dl里 居中,底部对齐
2008/01/21 Javascript
为radio类型的INPUT添加客户端脚本(附加实现JS来禁用onClick事件思路代码)
2010/11/11 Javascript
鼠标选择动态改变网页背景颜色的JS代码
2013/12/10 Javascript
javascript实例分享---具有立体效果的图片特效
2014/06/08 Javascript
浅谈jquery页面初始化的4种方式
2016/11/27 Javascript
JS编写函数实现对身份证号码最后一位的验证功能
2016/12/29 Javascript
如何将 jQuery 从你的 Bootstrap 项目中移除(取而代之使用Vue.js)
2017/07/17 jQuery
js实现多张图片延迟加载效果
2017/07/17 Javascript
微信小程序如何获取openid及用户信息
2018/01/26 Javascript
axios+Vue实现上传文件显示进度功能
2019/04/14 Javascript
使用ThinkJs搭建微信中控服务的实现方法
2019/08/08 Javascript
layui写后台表格思路和赋值用法详解
2019/11/14 Javascript
[00:35]可解锁地面特效
2018/12/20 DOTA
[01:51]2018年度CS GO最具人气外援-完美盛典
2018/12/16 DOTA
Python常用内置函数总结
2015/02/08 Python
python实现人人自动回复、抢沙发功能
2018/06/08 Python
python读取目录下最新的文件夹方法
2018/12/24 Python
python tkinter实现界面切换的示例代码
2019/06/14 Python
python程序 创建多线程过程详解
2019/09/23 Python
python运用pygame库实现双人弹球小游戏
2019/11/25 Python
python绘制彩虹图
2019/12/16 Python
打印tensorflow恢复模型中所有变量与操作节点方式
2020/05/26 Python
名词解释WEB SERVICE,SOAP,UDDI,WSDL,JAXP,JAXM;JSWDL开发包的介绍。
2012/10/27 面试题
医学生个人求职信范文
2013/09/24 职场文书
迅雷Cued工作心得体会
2014/01/27 职场文书
班干部竞选演讲稿
2014/04/24 职场文书
听课评语大全
2014/04/30 职场文书
学雷锋先进个人事迹
2014/05/26 职场文书
清明节演讲稿
2014/05/27 职场文书
中韩经贸翻译专业大学生职业生涯规划范文
2014/09/18 职场文书
九寨沟导游词
2015/02/02 职场文书
2015年办公室文秘工作总结
2015/04/30 职场文书