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 相关文章推荐
js拼接html注意问题示例探讨
Jul 14 Javascript
TinyMCE提交AjaxForm获取不到数据的解决方法
Mar 05 Javascript
原生js实现百叶窗效果及原理介绍
Apr 12 Javascript
jQuery EasyUI提交表单验证
Jul 19 Javascript
js cookie实现记住密码功能
Jan 17 Javascript
JS在if中的强制类型转换方式
Jul 15 Javascript
ajax与jsonp的区别及用法
Oct 16 Javascript
jQuery实现input输入框获取焦点与失去焦点时提示的消失与显示功能示例
May 27 jQuery
基于jQuery的时间戳与日期间的转化
Jun 21 jQuery
Vue 解决路由过渡动画抖动问题(实例详解)
Jan 05 Javascript
微信小程序文章列表功能完整实例
Jun 03 Javascript
如何利用JavaScript编写一个格斗小游戏
Jan 06 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
vBulletin HACK----关于排版的两个HACK
2006/10/09 PHP
php email邮箱正则
2008/10/08 PHP
深入解析PHP内存管理之谁动了我的内存
2013/06/20 PHP
php tpl模板引擎定义与使用示例
2019/08/09 PHP
TNC vs BOOM BO3 第一场2.13
2021/03/10 DOTA
Array.slice()与Array.splice()的返回值类型
2006/10/09 Javascript
写了10年的Javascript也未必全了解的连续赋值运算
2011/03/25 Javascript
javascript模拟订火车票和退票示例
2014/04/24 Javascript
基于JavaScript实现随机颜色输入框
2016/12/10 Javascript
原生JS实现跑马灯效果
2017/02/20 Javascript
浅谈jQuery的bind和unbind事件(绑定和解绑事件)
2017/03/02 Javascript
NodeJS实现微信公众号关注后自动回复功能
2017/05/31 NodeJs
JavaScript代码执行的先后顺序问题
2017/10/29 Javascript
react配合antd组件实现的管理系统示例代码
2018/04/24 Javascript
[32:30]夜魇凡尔赛茶话会 第一期01:谁是卧底
2021/03/11 DOTA
Python 调用DLL操作抄表机
2009/01/12 Python
pycharm远程调试openstack代码
2017/11/21 Python
对pycharm 修改程序运行所需内存详解
2018/12/03 Python
使用Python做定时任务及时了解互联网动态
2019/05/15 Python
python爬虫 基于requests模块发起ajax的get请求实现解析
2019/08/20 Python
windows支持哪个版本的python
2020/07/03 Python
基于python实现百度语音识别和图灵对话
2020/11/02 Python
详解CSS3的perspective属性设置3D变换距离的方法
2016/05/23 HTML / CSS
css3实现背景动态渐变效果
2019/12/10 HTML / CSS
CSS3选择器新增问题的实现
2021/01/21 HTML / CSS
html5记忆翻牌游戏实现思路及代码
2013/07/25 HTML / CSS
html5 canvas实现圆形时钟代码分享
2013/12/25 HTML / CSS
施华洛世奇日本官网:SWAROVSKI日本
2018/05/04 全球购物
荷兰家电购物网站:Expert.nl
2020/01/18 全球购物
办公室文秘岗位职责
2013/11/15 职场文书
共产党员承诺书
2014/03/25 职场文书
婚前财产协议书范本
2014/10/19 职场文书
防汛工作情况汇报
2014/10/28 职场文书
酒店辞职信怎么写
2015/02/27 职场文书
材料员岗位职责范本
2015/04/11 职场文书
sql注入教程之类型以及提交注入
2021/08/02 MySQL