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 相关文章推荐
如何书写高质量jQuery代码(使用jquery性能问题)
Jun 30 Javascript
js的for in循环和java里foreach循环的区别分析
Jan 28 Javascript
JS判断是否360安全浏览器极速内核的方法
Jan 29 Javascript
一分钟理解js闭包
May 04 Javascript
AngularJS基础 ng-include 指令示例讲解
Aug 01 Javascript
localStorage的黑科技-js和css缓存机制
Feb 06 Javascript
js绑定事件和解绑事件
Apr 27 Javascript
详解ajax的data参数错误导致页面崩溃
Apr 30 Javascript
Vue项目webpack打包部署到Tomcat刷新报404错误问题的解决方案
May 15 Javascript
关于在vue 中使用百度ueEditor编辑器的方法实例代码
Sep 14 Javascript
web页面和微信小程序页面实现瀑布流效果
Sep 26 Javascript
如何检查一个对象是否为空
Apr 11 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实现将字符串按照指定距离进行分割的方法
2015/03/14 PHP
laravel 获取某个查询的查询SQL语句方法
2019/10/12 PHP
JavaScript 保存数组到Cookie的代码
2010/04/14 Javascript
基于jquery的仿百度搜索框效果代码
2011/04/11 Javascript
当jQuery1.7遇上focus方法的问题
2014/01/26 Javascript
JavaScript通过function定义对象并给对象添加toString()方法实例分析
2015/03/23 Javascript
jQuery实现简单二级下拉菜单
2015/04/12 Javascript
全面解析Bootstrap中Carousel轮播的使用方法
2016/06/13 Javascript
超简单的Vue.js环境搭建教程
2017/03/17 Javascript
AngularJS+Bootstrap3多级导航菜单的实现代码
2017/08/16 Javascript
深入理解requireJS-实现一个简单的模块加载器
2018/01/15 Javascript
Javascript Promise用法详解
2018/05/10 Javascript
jQuery获取随机颜色的实例代码
2018/05/21 jQuery
浅谈vue.use()方法从源码到使用
2019/05/12 Javascript
google广告之另类js调用实现代码
2020/08/22 Javascript
[00:10]DOTA2全国高校联赛 以DOTA2会友
2018/05/30 DOTA
[01:03:03]VP vs Mineski 2018国际邀请赛淘汰赛BO3 第一场 8.22
2018/08/23 DOTA
Python 把序列转换为元组的函数tuple方法
2019/06/27 Python
Django 实现图片上传和显示过程详解
2019/07/18 Python
django model 条件过滤 queryset.filter(**condtions)用法详解
2020/05/20 Python
在 Windows 下搭建高效的 django 开发环境的详细教程
2020/07/27 Python
python 爬虫如何正确的使用cookie
2020/10/27 Python
HTML5拖放效果的实现代码
2016/11/17 HTML / CSS
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
英国汽车座椅和婴儿车购物网站:Uber Kids
2017/04/19 全球购物
奢华时尚的创新平台:Baltini
2020/10/03 全球购物
什么是虚拟内存?虚拟内存有什么优势?
2016/02/09 面试题
艺术系大学生毕业个人自我评价
2013/09/19 职场文书
2015年会计个人工作总结
2015/04/02 职场文书
职位证明模板
2015/06/23 职场文书
2016大学生求职自荐信范文
2016/01/28 职场文书
你会写报告?产品体验报告到底该怎么写?
2019/08/14 职场文书
mybatis中注解与xml配置的对应关系和对比分析
2021/08/04 Java/Android
Vue+Flask实现图片传输功能
2022/04/01 Vue.js
Nginx本地配置SSL访问的实例教程
2022/05/30 Servers
CSS使用SVG实现动态分布的圆环发散路径动画
2022/12/24 HTML / CSS