Node.js搭建WEB服务器的示例代码


Posted in Javascript onAugust 15, 2018

前言

这几天为了熟悉vue.js框架,还有webpack的使用,就准备搭建一个发布和浏览markdwon的简单WEB应用。原本是想着用bash脚本和busybox的httpd来作为后台服务,但是bash脚本解析和生成JSON非常不方便,而用Java语言写又觉得部署不方便,所以就想到了正在用到的Node.js,于是就有了这篇博文。(文末有本文代码的github地址)

简单例子

首先,从搭建最简单的 Hello world 开始,建立以下目录、文件和内容。

建立项目及运行

project

web-server
+ | - server.js

server.js

const http = require('http');

http.createServer(function(request, response) {
 // 设置响应头
 response.writeHeader(200, {
  "Content-Type" : "text/plain"
 });
 // 响应主体为 "Hello world!"
 response.write("Hello world!");
 response.end();
})
// 设置监听端口为9000
.listen(9000);

现在,在项目目录运行下面命令来执行 server.js ,浏览器地址栏中输入 localhost:9000 ,如果一切访问都正常,浏览器就会显示 Hello world! 。

node server.js

提示:使用 ctrl+c 停止脚本运行。

至此一个简单例子就运行成功了,下面来分析一下代码。

代码分析

首先, server.js 中引入了Node.js的 http模块 ,它提供了非常底层HTTP API支持。这里使用 createServer() 方法,它返回一个 http.server 实例,使用该实例的 listen() 方法来设置监听端口。

方法 createSever() 中填写的参数是一个函数,该函数会作为回调函数自动添加到 request事件 去,其参数类型分别为 http.IncomingMessage 和 http.ServerResponse 。在回调函数体里,利用 http.ServerResponse 的方法设置了响应头和响应主体,最后以 end() 方法结束本次请求。

路由功能

上述的例子仅仅实现了简单请求响应功能,现在增加路由的功能来健壮我们的WEB服务器。现在,修改为以下的目录、文件和内容。

实现简单路由

project

web-server
 | - server.js
+ | - router.js

server.js

const http = require('http');
const router = require('./router.js');

function handleHello(request, response) {
 // 设置响应头
 response.writeHeader(200, {
  "Content-Type" : "text/plain"
 });
 // 响应主体为 "Hello world!"
 response.write("Hello world!");
 response.end();
}

http.createServer(function(request, response) {
 // 注册路径和其对应回调函数
 router.register(request, response, [
  {
   'url': '/hello',
   'handler': handleHello
  }
 ]);
})
// 设置监听端口为9000
.listen(9000);

router.js

const url = require('url');

exports.register = function(request, response, mapping) {
 // 解析请求路径
 var pathName = url.parse(request.url).pathname;
 // 执行相应请求路径的回调函数
 for(let i = 0, len = mapping.length;i < len;i++) {
  if(mapping[i].url === pathName) {
   mapping[i].handler(request, response);
   return;
  }
 }
 // 请求路径不存在返回404页面
 response.writeHeader(404, {
  "Content-Type" : "text/html"
 });
 response.end(`
  <html>
   <head>
    <title>NOT FOUND</title>
   </head>
   <body>
    <h1>404 NOT FOUND</h1>
   </body>
  </html>
 `);
}

现在,再次执行 server.js 脚本,接着浏览器访问 localhost:9000\hello 会得到 Hello world! 的结果,而访问其他路径则会得到404页面。

这个功能的核心实现是在 router.js 中,通过请求路径的解析,然后根据预先注册好的 mapping 数组,找到与之对应的路径并执行相应的回调函数。

静态资源请求

当前的路由功能只能实现回调函数的执行,而一个WEB服务器应具有响应静态资源请求的能力,接下我们继续来改造它。现在,保持 server.js 内容不变,只改变 router.js 中的内容(部分代码内容省略)。

route.js

const url = require('url');
const path = require('path');
const fs = require('fs');

function getErrorInfo(errorType) {
 // 省略代码
}

function writeErrorPage(response, errorType) {
 // 省略代码
}

exports.register = function(request, response, mapping) {
 // 解析请求路径
 var pathName = url.parse(request.url).pathname;
 // 执行相应请求路径的回调函数
 for(let i = 0, len = mapping.length;i < len;i++) {
  if(mapping[i].url === pathName) {
   mapping[i].handler(request, response);
   return;
  }
 }
 // 请求路径为文件返回文件内容
 var file = path.resolve(__dirname, '.' + pathName);
 fs.exists(file, function(exists) {
  // 请求路径不存在返回404页面
  if(!exists) {
   writeErrorPage(response, 'NOT_FOUND');
  }
  else {
   var stat = fs.statSync(file);
   // 请求路径为目录返回403页面
   if(stat.isDirectory()) {
    writeErrorPage(response, 'FORBIDDEN');
   }
   else {
    response.writeHeader(200, {
     "Content-Type" : "text/html"
    });
    response.end(
     fs.readFileSync(file, 'utf-8')
    );
   }
  }
 });
}

将静态资源请求的行为置后的设计,是为了保证回调函数一定能执行。当静态资源不存在时,应当返回不存在的错误,同时也设置了禁止目录的访问的规则。

后话

现在,只是实现了WEB服务器基本的功能,它还有很大的改进空间。我将项目开源到 github 上,有兴趣的可以克隆下来。希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
javascript网页关键字高亮代码
Jul 30 Javascript
ajax 文件上传应用简单实现
Mar 03 Javascript
JavaScript 开发中规范性的一点感想
Jun 23 Javascript
JQuery中的ready函数冲突的解决方法
May 17 Javascript
ExtJS PropertyGrid中使用Combobox选择值问题
Jun 13 Javascript
javascript动态控制服务器控件实例
Sep 05 Javascript
JavaScript创建一个object对象并操作对象属性的用法
Mar 23 Javascript
javascript实现的简单的表单验证
Jul 10 Javascript
JS获取时间的相关函数及时间戳与时间日期之间的转换
Feb 04 Javascript
微信小程序 富文本转文本实例详解
Oct 24 Javascript
ES6扩展运算符的用途实例详解
Aug 20 Javascript
解决layui下拉框监听问题(监听不到值的变化)
Sep 28 Javascript
Layui 设置select下拉框自动选中某项的方法
Aug 14 #Javascript
vue升级之路之vue-router的使用教程
Aug 14 #Javascript
layui table 参数设置方法
Aug 14 #Javascript
layui 表格的属性的显示转换方法
Aug 14 #Javascript
JS中数组与对象的遍历方法实例小结
Aug 14 #Javascript
layui实现table加载的示例代码
Aug 14 #Javascript
layui点击导航栏刷新tab页的示例代码
Aug 14 #Javascript
You might like
雄兵连:天使彦天使彦为爱折翼,彦和炙心同时念动的誓言!
2020/03/02 国漫
thinkPHP数据库增删改查操作方法实例详解
2016/12/06 PHP
Yii2中datetime类的使用
2016/12/17 PHP
php正则提取html图片(img)src地址与任意属性的方法
2017/02/08 PHP
laravel在中间件内生成参数并且传递到控制器中的2种姿势
2019/10/15 PHP
页面调用单个swf文件,嵌套出多个方法。
2011/11/21 Javascript
JQuery记住用户名和密码的具体实现
2014/04/04 Javascript
简单谈谈jQuery(function(){})与(function(){})(jQuery)
2014/12/19 Javascript
JavaScript随机生成信用卡卡号的方法
2015/04/07 Javascript
jQuery ajax请求返回list数据动态生成input标签,并把list数据赋值到input标签
2016/03/29 Javascript
基于JS实现Android,iOS一个手势动画效果
2016/04/27 Javascript
小程序自定义组件实现城市选择功能
2018/07/18 Javascript
vue项目中在外部js文件中直接调用vue实例的方法比如说this
2019/04/28 Javascript
浅谈vue中使用编辑器vue-quill-editor踩过的坑
2020/08/03 Javascript
[00:32]2018DOTA2亚洲邀请赛OpTic出场
2018/04/03 DOTA
Python中每次处理一个字符的5种方法
2015/05/21 Python
Python实现将Excel转换成为image的方法
2018/10/23 Python
OpenCV-Python 摄像头实时检测人脸代码实例
2019/04/30 Python
Python利用WMI实现ping命令的例子
2019/08/14 Python
python程序需要编译吗
2020/06/19 Python
Keras搭建自编码器操作
2020/07/03 Python
pycharm2020.1.2永久破解激活教程,实测有效
2020/10/29 Python
纯CSS3实现的阴影效果
2014/12/24 HTML / CSS
Ray-Ban雷朋西班牙官网:全球领先的太阳眼镜品牌
2018/11/28 全球购物
AVI-8手表美国官方商店:AVI-8 USA
2019/04/10 全球购物
中国制造网:Made-in-China.com
2019/10/25 全球购物
C#面试题
2016/05/06 面试题
食品安全检查制度
2014/02/03 职场文书
预备党员2014全国两会学习心得体会
2014/03/10 职场文书
幼儿园教师师德师风演讲稿:爱我所爱 无悔青春
2014/09/10 职场文书
2015年个人剖析材料范文
2014/12/29 职场文书
中标通知书范本
2015/04/17 职场文书
安全教育培训制度
2015/08/06 职场文书
如何做好工作总结!
2019/04/10 职场文书
人生感悟经典句子
2019/08/20 职场文书
CSS实现九宫格布局(自适应)的示例代码
2022/02/12 HTML / CSS