Node 学习 -- 搭建简单的服务器

3,638 阅读3分钟

Node搭建一个简单的静态服务器,具备一些基本功能.

功能:

  • 能显示以.html/.htm结尾的Web页面
  • 能直接打开以.js/.css/.json/.text结尾的文件内容,以及图片
  • 查找文件/目录,如果不是文件是目录下,就列出该目录下所有文件及文件夹,并可以进一步访问
  • 规定url进行重定向

Node重定向写法可以参考stackoverflow.com/questions/4…

我在文件里面设置了/static为静态资源的文件目录,因此http://localhost:8080/其实就是默认打开的就是D:\xxx\static

// server.js  这里其实应该对代码进行拆分下,稍微整洁点


const http = require('http');
const fs = require('fs');
const path = require('path');
const url = require('url');
var mime = require('./mime'); // 加载我们的mime.js
var config = require('./config');

const port = 8080;

const server =  http.createServer(function(req,res){

  var pathName = url.parse(req.url).pathname;  // 获取文件名"/xxx"

      // 对中文进行解码,防止乱码
      pathName = decodeURI(pathName);

      // 重定向: 考虑定义标准的url,以'/'结尾.
      if(path.extname(pathName) === ''){  // 没有扩展名
        if(pathName.charAt(pathName.length-1) !== '/'){
          pathName += '/';
          var redirect = encodeURI('http://' + req.headers.host + pathName); // 记得encodeURI,不然中文目录报错
          console.log(redirect);
          res.writeHead(301,{
            location: redirect
          });

        }
      }

      // 获取资源的绝对路径
      var realFilePath = path.resolve(__dirname+'/static'+ pathName);
      console.log(realFilePath);
      // 获取对应文件的文档类型
      var ext = path.extname(pathName); // 获取后缀名,如'.html'
      ext = ext?ext.slice(1): 'notKnow';  // 取掉.符号
      if (ext.match(config.Expires.fileMatch)) {
          var expires = new Date();
          expires.setTime(expires.getTime() + config.Expires.maxAge * 1000);
          // 设置响应头
          res.setHeader("Expires", expires.toUTCString());
          res.setHeader("Cache-Control", "max-age=" + config.Expires.maxAge);
      }
      // 定义未知文档的类型MIME
      var contentType = mime[ext] || "text/plain"; // 后缀名存在就进行映射,不存在就是'text/plain'

      // 判断文件是否存在
      fs.stat(realFilePath,function(err,stats){
        // err
        if(err){
          // 也可以定制自己的404页面
          res.writeHead(404,{'content-type': 'text/html'});
          res.end('<h3>404 Not Found</h3>');
        }
        // 存在
        if(stats.isFile()){
          console.log('is file');
          res.writeHead(200,{'content-type': contentType});
          // 开始读取文件
          var stream = fs.createReadStream(realFilePath);
          // 读取时候错误处理
          stream.on('error',function(){
            res.writeHead(500,{'content-type': contentType});
          });
          // 返回文件内容
          stream.pipe(res);
        }
        // 路径是目录的情况,列出当前目录下文件
        if(stats.isDirectory() ){

          var html = '<head><meta charset="utf-8"></head>';
          // 读写该目录下的内容 files是文件数组
          fs.readdir(realFilePath,function(err,files){
            if(err){
              console.log('目录文件读取失败');
            }else{
                console.log('is directory' + files); // test

              for(var i = 0;i < files.length;i++){
                //测当前目录下是否有index.html文件
                // if (files[i] === "index.html") {
                //   res.writeHead(200, { "content-type": "text/html" });
                //   res.end();
                //   break;
                // }
                html += "<div><a  href='"+files[i]+"'>"+files[i]+"</a></div>";
              }
            }
            res.writeHead(200,{'content-type': 'text/html'});
            res.end(html);
          });

        }
      });

}).listen(port,function(){
  console.log('Server running at port:' + port)
});
// config.js

exports.Expires = {
    fileMatch: /^(gif|png|jpg|js|css)$/ig, // 这只是个demo
    maxAge: 60 * 60 * 24 * 365
};
//mime.js  其实早就有这种模块的.

module.exports = {
    "css": "text/css",
    "gif": "image/gif",
    "html": "text/html",
    "ico": "image/x-icon",
    "jpeg": "image/jpeg",
    "jpg": "image/jpeg",
    "js": "text/javascript",
    "json": "application/json",
    "pdf": "application/pdf",
    "png": "image/png",
    "svg": "image/svg+xml",
    "swf": "application/x-shockwave-flash",
    "tiff": "image/tiff",
    "txt": "text/plain",
    "wav": "audio/x-wav",
    "wma": "audio/x-ms-wma",
    "wmv": "video/x-ms-wmv",
    "xml": "text/xml"
};

参考资料:www.infoq.com/cn/news/201…

我测试过是基本ok的.偶尔冒出以下错误.不知道是为什么.刷新一下又没有.懂得朋友请告知.
 if(stats.isFile()){
                ^
TypeError: Cannot read property 'isFile' of undefined