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 Date对象 学习
Jul 12 Javascript
基于jquery的finkyUI插件与Ajax实现页面数据加载功能
Dec 03 Javascript
jquery判断元素的子元素是否存在的示例代码
Feb 04 Javascript
关于延迟加载JavaScript
May 05 Javascript
JS中产生标识符方式的演变
Jun 12 Javascript
你知道setTimeout是如何运行的吗?
Aug 16 Javascript
Vue渲染函数详解
Sep 15 Javascript
微信小程序实现图片放大预览功能
Oct 22 Javascript
前端必备插件之纯原生JS的瀑布流插件Macy.js
Nov 22 Javascript
nvm、nrm、npm 安装和使用详解(小结)
Jan 17 Javascript
ajax jquery实现页面某一个div的刷新效果
Mar 04 jQuery
vue实现同时设置多个倒计时
May 20 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上传图片客户端和服务器端实现方法
2015/03/30 PHP
PHP魔术方法之__call与__callStatic使用方法
2017/07/23 PHP
用于节点操作的API,颠覆原生操作HTML DOM节点的API
2010/12/11 Javascript
jQuery探测位置的提示弹窗(toolTip box)详细解析
2013/11/14 Javascript
理解Angular数据双向绑定
2016/01/10 Javascript
jQuery判断浏览器并动态调整select宽度的方法
2016/03/02 Javascript
Node.js中文件操作模块File System的详细介绍
2017/01/05 Javascript
微信小程序中用WebStorm使用LESS
2017/03/08 Javascript
轻松实现jQuery添加删除按钮Click事件
2017/03/13 Javascript
socket.io学习教程之基本应用(二)
2017/04/29 Javascript
React中上传图片到七牛的示例代码
2017/10/10 Javascript
angular中子控制器向父控制器传值的实例
2018/10/08 Javascript
详解Vue+ElementUI从零开始搭建自己的网站(一、环境搭建)
2019/04/30 Javascript
elementUI select组件value值注意事项详解
2019/05/29 Javascript
p5.js实现故宫橘猫赏秋图动画
2019/10/23 Javascript
JavaScript复制变量三种方法实例详解
2020/01/09 Javascript
javascript读取本地文件和目录方法详解
2020/08/06 Javascript
js实现盒子拖拽动画效果
2020/08/09 Javascript
[02:28]DOTA2英雄基础教程 灰烬之灵
2013/12/19 DOTA
[02:49]DAC2018决赛日TOP5 LGD开启黑暗之门绝杀VP
2018/04/08 DOTA
[01:27:30]LGD vs Newbee 2019国际邀请赛小组赛 BO2 第二场 8.16
2019/08/19 DOTA
python批量提交沙箱问题实例
2014/10/08 Python
python代码编写计算器小程序
2020/03/30 Python
Python configparser模块配置文件过程解析
2020/03/03 Python
Python任务自动化工具tox使用教程
2020/03/17 Python
在 Python 中使用 7zip 备份文件的操作
2020/12/11 Python
HTML5实现获取地理位置信息并定位功能
2015/04/25 HTML / CSS
海外淘书首选:AbeBooks
2017/07/31 全球购物
Orlebar Brown官网:设计师泳裤和泳装
2020/12/08 全球购物
Java TransactionAPI (JTA) 主要包含几部分
2012/12/07 面试题
四年的大学生生活自我评价
2013/12/09 职场文书
幼儿园义卖活动方案
2014/01/17 职场文书
2014年财务工作总结与计划
2014/12/08 职场文书
同意落户证明
2015/06/19 职场文书
Python中可变和不可变对象的深入讲解
2021/08/02 Python
js面向对象编程OOP及函数式编程FP区别
2022/07/07 Javascript