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 相关文章推荐
My Desktop :) 桌面式代码
Dec 29 Javascript
jQuery 选择器项目实例分析及实现代码
Dec 28 Javascript
Ext JS添加子组件的误区探讨
Jun 28 Javascript
可兼容IE的获取及设置cookie的jquery.cookie函数方法
Sep 02 Javascript
JS实现三级折叠菜单特效,其它级可自动收缩
Aug 06 Javascript
js流动式效果显示当前系统时间
May 16 Javascript
微信小程序 页面跳转传递值几种方法详解
Jan 12 Javascript
jquery+ajax实现省市区三级联动 (封装和不封装两种方式)
May 15 jQuery
AngularJS ionic手势事件的使用总结
Aug 09 Javascript
node中的密码安全(加密)
Sep 17 Javascript
详解js location.href和window.open的几种用法和区别
Dec 02 Javascript
vue代码分块和懒加载非必要资源文件
Apr 11 Vue.js
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 和 MySQL 开发的 8 个技巧
2006/10/09 PHP
ThinkPHP关联模型操作实例分析
2012/09/23 PHP
jQuery方法简洁实现隔行换色及toggleClass的使用
2013/03/15 Javascript
Document.location.href和.replace的区别示例介绍
2014/03/04 Javascript
JavaScript操作HTML元素和样式的方法详解
2015/10/21 Javascript
基于JavaScript实现自定义滚动条
2017/01/25 Javascript
搭建vue开发环境
2018/07/19 Javascript
基于Vue实现关键词实时搜索高亮显示关键词
2018/07/21 Javascript
vue操作下拉选择器获取选择的数据的id方法
2018/08/24 Javascript
微信小程序与后台PHP交互的方法实例分析
2018/12/10 Javascript
小程序关于请求同步的总结
2019/05/05 Javascript
react MPA 多页配置详解
2019/10/18 Javascript
JavaScript命令模式原理与用法实例详解
2020/03/10 Javascript
JS实现斐波那契数列的五种方式(小结)
2020/09/09 Javascript
解决Vue keep-alive 调用 $destory() 页面不再被缓存的情况
2020/10/30 Javascript
Angular处理未可知异常错误的方法详解
2021/01/17 Javascript
Python程序打包工具py2exe和PyInstaller详解
2019/06/28 Python
python中的 zip函数详解及用法举例
2020/02/16 Python
使用pyecharts1.7进行简单的可视化大全
2020/05/17 Python
Keras-多输入多输出实例(多任务)
2020/06/22 Python
解决Windows下python和pip命令无法使用的问题
2020/08/31 Python
HTML5离线缓存在tomcat下部署可实现图片flash等离线浏览
2012/12/13 HTML / CSS
HTML5+CSS设置浮动却没有动反而在中间且错行的问题
2020/05/26 HTML / CSS
英国护肤品购物网站:Beauty Expert
2016/08/19 全球购物
Kidsroom台湾:来自德国的婴儿用品
2017/12/11 全球购物
捷克领先的户外服装及配件市场零售商:ALPINE PRO
2018/01/09 全球购物
新加坡第一大健康与美容零售商:屈臣氏新加坡(Watsons Singapore)
2020/12/11 全球购物
C#可否对内存进行直接的操作
2015/02/26 面试题
如何现实servlet的单线程模式
2014/08/05 面试题
城市轨道专业个人求职信范文
2013/09/23 职场文书
毕业生应聘幼儿园的自荐信
2013/11/20 职场文书
优秀乡村医生事迹材料
2014/05/28 职场文书
2014年医院党建工作总结
2014/12/20 职场文书
试用期解除劳动合同通知书
2015/04/16 职场文书
2016春季田径运动会广播稿
2015/12/21 职场文书
python数据处理之Pandas类型转换
2022/04/28 Python