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 相关文章推荐
IE7中javascript操作CheckBox的checked=true不打勾的解决方法
Dec 07 Javascript
getElementByIdx_x js自定义getElementById函数
Jan 24 Javascript
file模式访问网页时iframe高度自适应解决方案
Jan 16 Javascript
jquery struts 验证唯一标识(公用方法)
Mar 27 Javascript
js实时获取系统当前时间实例代码
Jun 28 Javascript
jQuery实现仿Google首页拖动效果的方法
May 04 Javascript
jQuery实现Flash效果上下翻动的中英文导航菜单代码
Sep 22 Javascript
angular2使用简单介绍
Mar 01 Javascript
jQuery扩展_动力节点Java学院整理
Jul 05 jQuery
Ionic学习日记实现验证码倒计时
Feb 08 Javascript
axios使用拦截器统一处理所有的http请求的方法
Nov 02 Javascript
javascript Number 与 Math对象的介绍
Nov 17 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
php数组中删除元素的实现代码
2012/06/22 PHP
JavaScript高级程序设计 读书笔记之九 本地对象Array
2012/02/27 Javascript
js实现弹窗插件功能实例代码分享
2013/12/12 Javascript
js实现简易的单数字随机抽奖(0-9)
2020/03/19 Javascript
jQuery+PHP星级评分实现方法
2015/10/02 Javascript
微信小程序实现图片自适应(支持多图)
2017/01/25 Javascript
使用vue构建一个上传图片表单
2017/07/04 Javascript
解析Vue 2.5的Diff算法
2017/11/28 Javascript
微信小程序实现图片上传功能实例(前端+PHP后端)
2018/01/10 Javascript
vue用递归组件写树形控件的实例代码
2018/07/19 Javascript
vue-cli监听组件加载完成的方法
2018/09/07 Javascript
JS中使用new Option()实现时间联动效果
2018/12/10 Javascript
Postman环境变量全局变量使用方法详解
2020/08/13 Javascript
解决vue项目中某一页面不想引用公共组件app.vue的问题
2020/08/14 Javascript
[01:04]不如跳舞!DOTA2新英雄玛尔斯的欢乐日常
2019/03/11 DOTA
[11:44]Ti9 OG夺冠时刻
2019/08/25 DOTA
深入了解Python数据类型之列表
2016/06/24 Python
Python 元类实例解析
2018/04/04 Python
TensorFlow 合并/连接数组的方法
2018/07/27 Python
python虚拟环境完美部署教程
2019/08/06 Python
python cv2截取不规则区域图片实例
2019/12/21 Python
Tensorflow Summary用法学习笔记
2020/01/10 Python
哪种Python框架适合你?简单介绍几种主流Python框架
2020/08/04 Python
10分钟入门CSS3 Animation
2018/12/25 HTML / CSS
美国知名运动产品零售商:Foot Locker
2016/07/23 全球购物
印度最大的网上花店:Ferns N Petals(鲜花、礼品和蛋糕)
2017/10/16 全球购物
新英格兰最大的特色礼品连锁店:The Paper Store
2018/07/23 全球购物
北京天润融通.net面试题笔试题
2012/02/20 面试题
启动仪式策划方案
2014/06/14 职场文书
企业党员个人自我评价
2014/09/20 职场文书
施工单位工程部经理岗位职责
2015/04/09 职场文书
幼儿园安全教育随笔
2015/08/14 职场文书
教师教育教学随笔
2015/08/15 职场文书
2019年教师节活动策划方案
2019/09/09 职场文书
pdf论文中python画的图Type 3 fonts字体不兼容的解决方案
2021/04/24 Python
Vue如何清空对象
2022/03/03 Vue.js