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 相关文章推荐
Prototype RegExp对象 学习
Jul 19 Javascript
学习ExtJS table布局
Oct 08 Javascript
JavaScript的漂亮的代码片段
Jun 05 Javascript
跨域传值即主页面与iframe之间互相传值
Dec 09 Javascript
jquery的each方法使用示例分享
Mar 25 Javascript
JavaScript设计模式之单件模式介绍
Dec 28 Javascript
IONIC自定义subheader的最佳解决方案
Sep 22 Javascript
React如何将组件渲染到指定DOM节点详解
Sep 08 Javascript
axios全局请求参数设置,请求及返回拦截器的方法
Mar 05 Javascript
Bootstrap 模态框自定义点击和关闭事件详解
Aug 10 Javascript
VueCli3.0中集成MockApi的方法示例
Jul 05 Javascript
layui在form表单页面通过Validform加入简单验证的方法
Sep 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
十大催泪虐心动漫电影,有几部你还没看
2020/03/04 日漫
在apache下限制每个虚拟主机的并发数!!!!
2006/10/09 PHP
PHPShop存在多个安全漏洞
2006/10/09 PHP
探讨PHP删除文件夹的三种方法
2013/06/09 PHP
PHP封装的Twitter访问类实例
2015/07/18 PHP
PHP的全局错误处理详解
2016/04/25 PHP
PHP写API输出的时用echo的原因详解
2019/04/28 PHP
PHP论坛实现积分系统的思路代码详解
2020/06/01 PHP
PHP时间类完整代码实例
2021/02/26 PHP
Javascript 判断 object 的特定类转载
2007/02/01 Javascript
利用js实现前台动态添加文本框,后台获取文本框内容(示例代码)
2013/11/25 Javascript
Bootstrap中点击按钮后变灰并显示加载中实例代码
2016/09/23 Javascript
JavaScript 中对象的深拷贝
2016/12/04 Javascript
jQuery Mobile漏洞会有跨站脚本攻击风险
2017/02/12 Javascript
vue-cli 目录结构详细讲解总结
2019/01/15 Javascript
vue项目使用$router.go(-1)返回时刷新原来的界面操作
2020/07/26 Javascript
Vue3.0的优化总结
2020/10/16 Javascript
Python实现在线暴力破解邮箱账号密码功能示例【测试可用】
2017/09/06 Python
点球小游戏python脚本
2018/05/22 Python
Python3数据库操作包pymysql的操作方法
2018/07/16 Python
python多进程下实现日志记录按时间分割
2019/07/22 Python
tensorflow tf.train.batch之数据批量读取方式
2020/01/20 Python
装上这 14 个插件后,PyCharm 真的是无敌的存在
2021/01/11 Python
python数据抓取3种方法总结
2021/02/07 Python
50个强大璀璨的CSS3/JS技术运用实例
2010/02/27 HTML / CSS
瑞典领先的汽车零部件网上零售商:bildelaronline24.se
2017/01/12 全球购物
全球最大的中文旅行网站:去哪儿网
2017/11/16 全球购物
手工制作的意大利皮革运动鞋:KOIO
2020/01/05 全球购物
彪马香港官方网上商店:PUMA香港
2020/12/06 全球购物
毕业生毕业总结的自我评价范文
2013/11/02 职场文书
销售经理工作职责范文
2013/12/03 职场文书
高中生期中考试失利检讨书
2014/10/23 职场文书
2015教师个人工作总结范文
2015/03/31 职场文书
酒店仓管员岗位职责
2015/04/01 职场文书
详解用Python把PDF转为Word方法总结
2021/04/27 Python
Pytorch GPU内存占用很高,但是利用率很低如何解决
2021/06/01 Python