转载

HTTP文件浏览(静态文件+express4.x+md/code文件渲染)

问题暴露

之前做的 HTTP浏览 是使用express2.x版本做的...,因为参考书比较旧了。

  1. express2.x 中没有 express4.x 中的 res.sendFile() 方法,之前发送文件是使用的 stream.pipe() 方法,导致不支持继续下载,而且用户不能知道下载进度,在线音乐视频播放也不能选择时间跳跃欣赏。 res.sendFile() 方法可以将本地文件以静态资源发送给用户,所有问题迎刃而解。

  2. 旧版本不支持 java/c/cpp/js/css/html 等代码文件和 md/markdown 文件在线查看,所以进行改进。

  3. 利用 Bootstrap responsive utilsBootstrap grid system 进行响应式布局。

  4. 监控 root.txt 文件,改变root后无需重启服务器。

  5. 去除对 q.js 依赖,使用原生 Promise

效果预览

  • json 文件查看

    HTTP文件浏览(静态文件+express4.x+md/code文件渲染)

  • md 文件查看

    HTTP文件浏览(静态文件+express4.x+md/code文件渲染)

  • html 文件查看

    HTTP文件浏览(静态文件+express4.x+md/code文件渲染)

代码改进

root.txt 文件监控

//全局对象 global.root = fs.readFileSync('./root.txt').toString().split(//s+/)[0]; fs.watchFile('./root.txt',function () {   //root.txt 文件修改后触发   global.root = fs.readFileSync('./root.txt').toString().split(//s+/)[0]; });

原生 Promise

var statP = function(root,file){     return new Promise(function(resolve){       fs.stat(root+'/'+file,function (err, stats) {         var t = {};         if(err){             t.reason=err;             resolve(t);         }         else {            t.state='ok';            stats.name = file;            stats.type = stats.isDirectory()?'文件夹':'文件';            t.value=stats;            resolve(t);         }       });     }) }; Promise.all(files.map((x,i,a)=>{return statP(r,x);}))     .then(function (results) {         var values = [];         results.forEach(x=>{             if(x.state==='ok'){                 values.push(x.value);             }else                 console.error(x.reason);         });         //...render     },console.error);

sendFile 方法使用

// noraw为url上的noraw参数值 if(!!noraw){     // f为文件名     if(f.match(//.(avi|mp4|mkv|rmvb|mpg|rm|wma)$/i)){         res.render('video',o);     }else if(f.match(//.(jpg|png|bmp|jpeg|gif)$/i)){         res.render('img',o);     }else if(f.match(//.(mp3|wma|aac)$/i)){         res.render('audio',o);     }else if(f.match(//.(md|markdown)$/i)){         fs.readFile(file,(error,data) => {             if(error) throw error;             o.content = data.toString();             res.render('md',o);         });     }else if(f.match(//.(java|c|cpp|js|css|jsp|php|json|txt)$/i)){         fs.readFile(file,(error,data) => {             if(error) throw error;             // 在服务器渲染高亮代码方法被淘汰,因为对大文件调用下面方法十分耗时间,             // 而node为单线程,所以其他用户请求也会被阻塞,而且本用户也要等待很久。             // 所以选择在浏览器端解析。             // console.time('hl');             // o.content=hl.highlightAuto(data.toString()).value;             // console.timeEnd('hl');             o.content = data.toString();             res.render('code',o);         });     }else if(f.match(//.(html|htm)$/i)){         fs.readFile(file,(error,data) => {             if(error) throw error;             o.content = data.toString();             res.render('html',o);         });     }else{         // rela 为相对路径,root 为文件根目录         res.sendFile(rela,{root:global.root});     } }else{     res.sendFile(rela,{root:global.root}); }

layout.jade

doctype html(lang="zh")   head     title= title     meta(name="renderer",content="webkit")     meta(http-equiv="X-UA-Compatible",content="IE=edge")     meta(name="viewport" content="width=device-width, initial-scale=1")     link(rel='stylesheet', href='/stylesheets/bootstrap.min.css')     link(rel='stylesheet', href='/stylesheets/style.css')     link(rel='stylesheet', href='/stylesheets/hljs-github.min.css')     link(rel='stylesheet', href='/stylesheets/pilcrow.css')     link(rel='stylesheet', href='/stylesheets/github-markdown.css')   body     block content

code.jade

extends layout  block content     script(src="http://cdn.bootcss.com/highlight.js/8.0/highlight.min.js")     div.container-fluid         h1=title         include btns         div.markdown-body             pre                 code!=content         script hljs.initHighlightingOnLoad();//自动寻找<pre><code></code></pre>进行解析         footer             p.text-center.text-info Running on node with Express, Jade. By Moyu.

md.jade

//    Created by Yc on 2016/6/9. extends layout  block content     script(src="http://cdn.bootcss.com/marked/0.3.5/marked.min.js")     script(src="http://cdn.bootcss.com/highlight.js/8.0/highlight.min.js")     div.container-fluid         h1=title         include btns         div.row             div.col-lg-6.visible-lg                 h2 解析前                 div.markdown-body                     pre                         code(id='markdown-raw')=content //"="会被转义(如 < : <),"!="不会             div.col-lg-6                 h2 解析后                 div.markdown-body(id='markdown-show')         script(src="/javascripts/md.js")         //renderer 来自md.js         script document.getElementById('markdown-show').innerHTML = marked(document.getElementById('markdown-raw').innerText,{renderer:renderer});         footer             p.text-center.text-info Running on node with Express, Jade. By Moyu.

md.js

~function(){     marked.setOptions({         highlight: function (code) {             return hljs.highlightAuto(code).value;         }     });     renderer = new marked.Renderer();     var map = {};     //重写默认'#','##'... 格式的转换方法     renderer.heading = function (text, level) {//level 表示层级,如#为1,##为2         var escapedText = text.toLowerCase();         // 防止出现重复的锚点         if(!!map[text])             escapedText+='-'+map[text]++;         else             map[text]=1;         return '<h' + level + '><a name="' +             escapedText +             '" class="anchor" href="#' +             escapedText +             '"><span class="header-link"></span></a>' +             text + '</h' + level + '>';     }; }();

问题归纳

通过url的noraw控制展示方式,对SEO不友好

GitHub的解决方法是,在raw文件提供独立的三级域名 raw.githubusercontent.com/{username}/{repo}/{branch}/{file}

后期希望更加完善这个web应用吧,比如在线查看压缩文件等功能。

代码地址

http-file-explorer-express4.x

参考资料

  • markdown-styles : 提供高大上的CSS样式。

  • marked : 提供强大的markdown格式转化API。

  • highlight.js : 提供强大的code格式转化为具有class样式的标签,方便用户自定义样式。

  • express4.x : express4.x详细API文档。

原文  https://segmentfault.com/a/1190000005683578
正文到此结束
Loading...