nodejs 实现的简单server.js模块 方便本地vue开发调试

ctee8715 8年前
   <p>因为最近在学习vue.js,需要渲染网页。但是搭建php的环境又感觉略复杂,所以用nodejs学习谢了一个server.js 用于方便自己本地的页面调试。要求的功能如下</p>    <ol>     <li> <p>支持html页面的访问</p> </li>     <li> <p>支持默认index.html、index.htm文件访问</p> </li>     <li> <p>支持路由+完整路径访问</p> </li>    </ol>    <p>关于第2条,访问 http://localhost.com:8080/vue/ 指向 vue/index.html文件</p>    <h3>项目地址</h3>    <p><a href="/misc/goto?guid=4959736860157159128" rel="nofollow,noindex">https://github.com/sunshinev/sunhuajie_node_server</a></p>    <h3>目录结构</h3>    <pre>  <code class="language-javascript">sunhuajie:node sun.huajie$ tree  .  ├── index.js // 启动服务的文件  ├── lyric.txt // 读写测试的文本文件  ├── node_modules  │   └── huajie_server // 自定义模块  │       ├── package.json // 模块配置  │       ├── requesthandler.js // 请求处理脚本  │       ├── router.js // 路由脚本  │       └── server.js // 服务创建脚本  └── vue // 工作目录      └── index.html</code></pre>    <h3>服务创建过程</h3>    <p>index.js 启动</p>    <p>因为将server封装为了一个模块,所以每次启动的时候只需要引入,然后node index.js就可以了。</p>    <pre>  <code class="language-javascript">#!/usr/bin/env node    var server = require('huajie_server');  server.create();</code></pre>    <p>效果如图:</p>    <pre>  <code class="language-javascript">sunhuajie:node sun.huajie$ node index.js  the port is 8080</code></pre>    <p>server.js 创建服务</p>    <p>_onRequest 实现了对请求的处理,并且作为闭包传递给 http.createServer 。状态码由路由层进行返回。</p>    <pre>  <code class="language-javascript">#!/usr/bin/env node    var http = require('http');  var router = require('./router');    // 创建server 默认端口为8080  function create(port = 8080) {      console.info('the port is '+port);      http.createServer(_onRequest).listen(port);  }    // 处理请求  function _onRequest(request, response) {      // 路由      var res = router.route(request.url);      // 状态码      response.writeHead(res.code,{});      // 响应内容      response.write(res.content);      response.end();  }    exports.create = create;</code></pre>    <p>router.js 路由</p>    <p>路由此处跟php的mvc的 dispatcher (分发器)很像,分析url参数以及目录,实现文件指向。 这里有个小问题,就是当时写这个router的时候,其实应该将 requesthandler.js 里面的关于文件判断的部分放到router里面才算合理。但是当时为了方便就直接写到requesthandler里面了(后面给大家看这个文件)。</p>    <p>在路由这一层,实际上还可以添加一个 rewrite 的配置。先分析 url ,通过 rewrite 重新指向后,再把指向后的地址传递给 requesthandler 进行处理。</p>    <pre>  <code class="language-javascript">#!/usr/bin/env node    var url = require('url');  var querystring = require('querystring');  var requesthandler = require('./requesthandler');    // todo 后期可以扩展路由部分    function route(request_url) {      // 解析地址      var url_parse = url.parse(request_url);      var url_path = url_parse['path'];            var res = {};      var code = 200;      // 判断路径是否存在      var content = requesthandler.handle(url_path);        return {          'code':code,          'content':content      }  }    exports.route = route;</code></pre>    <p>requesthandler.js 请求处理+文件指向</p>    <p>这个文件最简单的目的是实现对html文件的读取以及输出。但是我们加了一层默认文件,所以需要对目录进行遍历,并且判断当前的childnode是dir还是file。</p>    <p>默认可以访问 index.html 和 index.htm 两个文件。</p>    <p>_findFile 方法,首先判断当前传递的file_path是否是存在的文件,如果不是文件,那么在这个目录层级中进行搜索,是否存在默认可以访问的文件。进行遍历的时候,没有使用 forEach ,因为会遍历所有的文件,无论中间是否有 return 。</p>    <p>_isFile 方法,使用了try catch ,因为 fs.statSync 在文件不存在的时候,会抛出错误,导致脚本终止。</p>    <pre>  <code class="language-javascript">#!/usr/bin/env node    var fs = require('fs');    // 默认检索文件,可以修改为配置项  var default_files = [      'index.htm',      'index.html'  ];    function handle(url_path) {      // 文件路径构造      var file_path = '.' + url_path;      // 判断路径是否存在      var f_path = _findFile(file_path);            if(!f_path) {          return 'the path "'+file_path+'" is not exist';      }else {          var content = fs.readFileSync(f_path);          return content;      }  }  /**   * 检索目录下的不同文件名是否存在,建立优先级   * @return {[type]} [description]   */  function _findFile(file_path) {      var is_file = _isFile(file_path);      // 如果文件存在,直接返回路径      if(is_file) {          return file_path;      }      // 文件不存在,构造路径寻找文件      var regex = /^\.\/[\w]*([\/][\w]+)?/;      var regex_res = file_path.match(regex);      // 匹配出目录路径 ./vue/test/s => ./vue/test      if(!regex_res) {          return '';      }else {          // 这里没有使用forEach,因为会遍历所有的值          for(var i=0; i<default_files.length; i++) {              var new_path = regex_res[0]+'/'+default_files[i];              if(_isFile(new_path)) {                  return new_path;              }          }      }  }  /**   * 文件是否存在   * @param  {[type]}  file_path [description]   * @return {Boolean}           [description]   */  function _isFile(file_path) {      try {          // 同步会抛出异常,所以用try来保证正常执行          var stat = fs.statSync(file_path);          // 返回是否是文件          return stat.isFile();      }catch(e) {          console.info(e.message);      }              }    exports.handle = handle;</code></pre>    <h3>最终效果</h3>    <p>启动</p>    <pre>  <code class="language-javascript">sunhuajie:node sun.huajie$ node index.js  the port is 8080</code></pre>    <p>浏览器访问</p>    <table>     <thead>      <tr>       <th>访问</th>       <th>实际</th>      </tr>     </thead>     <tbody>      <tr>       <td>http://localhost:8080/vue/</td>       <td>指向 index.html</td>      </tr>      <tr>       <td>http://localhost:8080/vue</td>       <td>指向 index.html</td>      </tr>      <tr>       <td>http://localhost:8080/</td>       <td>the path "./" is not exist</td>      </tr>      <tr>       <td>http://localhost:8080/vue/s</td>       <td>the path "./vue/s" is not exist</td>      </tr>     </tbody>    </table>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000008307856</p>    <p> </p>