这几天为了熟悉vue.js框架,还有webpack的使用,就准备搭建一个发布和浏览markdwon的简单WEB应用。原本是想着用bash脚本和busybox的httpd来作为后台服务,但是bash脚本解析和生成JSON非常不方便,而用Java语言写又觉得部署不方便,所以就想到了正在用到的Node.js,于是就有了这篇博文。(文末有本文代码的github地址)

首先,从搭建最简单的Hello world开始,建立以下目录、文件和内容。

project

  1. web-server
  2. + | - server.js

server.js

  1. const http = require('http');
  2. http.createServer(function(request, response) {
  3. // 设置响应头
  4. response.writeHeader(200, {
  5. "Content-Type" : "text/plain"
  6. });
  7. // 响应主体为 "Hello world!"
  8. response.write("Hello world!");
  9. response.end();
  10. })
  11. // 设置监听端口为9000
  12. .listen(9000);

现在,在项目目录运行下面命令来执行server.js,浏览器地址栏中输入localhost:9000,如果一切访问都正常,浏览器就会显示Hello world!

  1. node server.js

提示:使用ctrl+c停止脚本运行。

至此一个简单例子就运行成功了,下面来分析一下代码。

首先,server.js中引入了Node.js的http模块,它提供了非常底层HTTP API支持。这里使用createServer()方法,它返回一个http.server实例,使用该实例的listen()方法来设置监听端口。

方法createSever()中填写的参数是一个函数,该函数会作为回调函数自动添加到request事件去,其参数类型分别为http.IncomingMessagehttp.ServerResponse。在回调函数体里,利用http.ServerResponse的方法设置了响应头和响应主体,最后以end()方法结束本次请求。

上述的例子仅仅实现了简单请求响应功能,现在增加路由的功能来健壮我们的WEB服务器。现在,修改为以下的目录、文件和内容。

project

  1. web-server
  2. | - server.js
  3. + | - router.js

server.js

  1. const http = require('http');
  2. const router = require('./router.js');
  3. function handleHello(request, response) {
  4. // 设置响应头
  5. response.writeHeader(200, {
  6. "Content-Type" : "text/plain"
  7. });
  8. // 响应主体为 "Hello world!"
  9. response.write("Hello world!");
  10. response.end();
  11. }
  12. http.createServer(function(request, response) {
  13. // 注册路径和其对应回调函数
  14. router.register(request, response, [
  15. {
  16. 'url': '/hello',
  17. 'handler': handleHello
  18. }
  19. ]);
  20. })
  21. // 设置监听端口为9000
  22. .listen(9000);

router.js

  1. const url = require('url');
  2. exports.register = function(request, response, mapping) {
  3. // 解析请求路径
  4. var pathName = url.parse(request.url).pathname;
  5. // 执行相应请求路径的回调函数
  6. for(let i = 0, len = mapping.length;i < len;i++) {
  7. if(mapping[i].url === pathName) {
  8. mapping[i].handler(request, response);
  9. return;
  10. }
  11. }
  12. // 请求路径不存在返回404页面
  13. response.writeHeader(404, {
  14. "Content-Type" : "text/html"
  15. });
  16. response.end(`
  17. <html>
  18. <head>
  19. <title>NOT FOUND</title>
  20. </head>
  21. <body>
  22. <h1>404 NOT FOUND</h1>
  23. </body>
  24. </html>
  25. `);
  26. }

现在,再次执行server.js脚本,接着浏览器访问localhost:9000\hello会得到Hello world!的结果,而访问其他路径则会得到404页面。

这个功能的核心实现是在router.js中,通过请求路径的解析,然后根据预先注册好的mapping数组,找到与之对应的路径并执行相应的回调函数。

当前的路由功能只能实现回调函数的执行,而一个WEB服务器应具有响应静态资源请求的能力,接下我们继续来改造它。现在,保持server.js内容不变,只改变router.js中的内容(部分代码内容省略)。

route.js

  1. const url = require('url');
  2. const path = require('path');
  3. const fs = require('fs');
  4. function getErrorInfo(errorType) {
  5. // 省略代码
  6. }
  7. function writeErrorPage(response, errorType) {
  8. // 省略代码
  9. }
  10. exports.register = function(request, response, mapping) {
  11. // 解析请求路径
  12. var pathName = url.parse(request.url).pathname;
  13. // 执行相应请求路径的回调函数
  14. for(let i = 0, len = mapping.length;i < len;i++) {
  15. if(mapping[i].url === pathName) {
  16. mapping[i].handler(request, response);
  17. return;
  18. }
  19. }
  20. // 请求路径为文件返回文件内容
  21. var file = path.resolve(__dirname, '.' + pathName);
  22. fs.exists(file, function(exists) {
  23. // 请求路径不存在返回404页面
  24. if(!exists) {
  25. writeErrorPage(response, 'NOT_FOUND');
  26. }
  27. else {
  28. var stat = fs.statSync(file);
  29. // 请求路径为目录返回403页面
  30. if(stat.isDirectory()) {
  31. writeErrorPage(response, 'FORBIDDEN');
  32. }
  33. else {
  34. response.writeHeader(200, {
  35. "Content-Type" : "text/html"
  36. });
  37. response.end(
  38. fs.readFileSync(file, 'utf-8')
  39. );
  40. }
  41. }
  42. });
  43. }

将静态资源请求的行为置后的设计,是为了保证回调函数一定能执行。当静态资源不存在时,应当返回不存在的错误,同时也设置了禁止目录的访问的规则。

现在,只是实现了WEB服务器基本的功能,它还有很大的改进空间。我将项目开源到github上,有兴趣的可以克隆下来。

版权声明:本文为linzhehuang原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/linzhehuang/p/9476771.html