分享一个 node.js “公众档所”项目 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
lock522
V2EX    程序员

分享一个 node.js “公众档所”项目

  •  4
     
  •   lock522 2015-09-14 16:09:46 +08:00 2820 次点击
    这是一个创建于 3684 天前的主题,其中的信息可能已经有所发展或是发生改变。

    本文作者:小死月 ,完整文章地址http://mp.weixin.qq.com/s?__biz=MjM5ODc5ODgyMw==&mid=210563292&idx=1&sn=d8a8ce1554fa1c510b357738a46f97a6#rd


    所谓“公众档所”,其实就是一个公共的临时网盘了。这个东西是一个老物了,在我刚接触 Expressjs 的时候写的。当时还随便搞了一下 backbone.js ,但是没有深入,勿笑。关于深入构架 Expressjs 方面也没做,只是粗粗写了下最基础的路由,所以整个文件结构也不是很规范。但是应该能比较适合刚学 Node.js 以及刚接触 Expressjs 的人吧。

    Repo 地址在 我的 Github (https://github.com/XadillaX/public-file-house)上。 Demo 地址在 http://dang.kacaka.ca/,由于个人电脑的不稳定性,所以不保证你们随时可以访问,保不定哪天就失效了,所以最好的办法还是自己 clone 下来啪啪啪。

    它所需要的东西大致就是 Expressjs + Redis + Backbone 了。不过都是最最基础的代码。

    部署

    把部署写在最前面是了能让你们自己电脑上有一个能跑的环境啦。公档所在我自己这边的环境里面是由三台电脑组成的。

    • 网关“服务器”。这是我这边环境一致对外的机器。实际上是一片树莓派,装了 nginx ,然后对内部做反向代理。
    • 本体“服务器”。跑了 公众档所 本体。
    • 数据库“服务器”。我们用的数据库实际上不是严格意义上的数据库,只是 redis 罢了,也没做与其它数据库的持久化,只是用了他内部自带的持久化。

    如果你们装一台机子上,那么就是:

    将 repo 给 clone 到自己的机子上。

    shell 1 $ git clone https://github.com/XadillaX/public-file-house 

    装好 redis ,并根据需要修改 redis.conf 文件。

    执行 redis.sh 文件开启数据库。如果你自己本身已经开启数据库或者用其它方法开了,请忽略上面数据库相关步骤。

    然后打开 commonConst.js 文件进行编辑,把相关的一些信息改成自己所需要的。

    哦对了,还有一个“洁癖相关”的步骤。我以前年轻不懂事,把 node_modules 文件夹也给加到版本库中了,而且也在里面居然自己加了两个没有弄到 nmp 去的模块(而且这两个模块本来就不应该放在这个文件夹下,但是不要在意这些细节,反正我现在肯定不会做这么傻的事了)。

    至于什麽不要这麽做,就跟 node_modules 文件夹的意义相关了。而且里面有可能有一些在我本机编译好的模块,所以最好还是清理下自己重新装一遍佳。

    具体呢大致就是把 node_modules 文件夹里面的 alphaRandomer.js 文件和 smpEncoder.js 文件拷贝出来备份到任意文件夹,然后删除整个 node _module 文件夹。接下去跑到项目根目录执行:

    shell 1 $ npm install 

    把三方模重新好之後,把拷出去的文件放回目下。(但是以後你自己的目的千我子啊,以前年不懂事 QAQ )

    最後跑起就行啦:

    shell 1 $ node pfh.js 

    解析

    接下去就是要剖析小破西了。

    基文件

    pfh.js

    文件其是 Expressjs 自生成的,以前不是很懂他,所以也怎,基本上是保持原封不的。

    router.js

    是路由定的文件。比陋的一方法,把需要定的所有路由都 json 象中,一 POST 和一 GET 。

    看 Expressjs 文的人或者教程的人都知道,最基的路由法其就是:

    Javascript 1 app.get (KEY, FUNCTION ); 

    或者:

    Javascript 1 app.post (KEY, FUNCTION ); 

    所以我下面有一函:

    Javascript 1 exports.setRouter = function (app ) { 2 for (var key in this.getRouter ) { 3 app.get (key, this.getRouter[key]); 4 } 5 6 for (var key in this.postRouter ) { 7 app.post (key, this.postRouter[key]); 8 } 9 }; 

    其大致意思就是把之前我定好的路由象的容一一到系的路由中去。是我最初最陋的思想,不後我把它稍稍完善了一下到的地方去了。

    模型

    model/fileModel.js

    就是模型了,主要就是 redis 的一些操作了。在我用的是 redis 模,具的用法大家可以看它 repo 的 README.md 文件。

    大致就三函:

    • fileModel.prototype.keyExists: 判某提取存在否。
    • fileModel.prototype.get: 取某的文件信息。
    • fileModel.prototype.addFile: 添加一文件信息。

    不有子大家不要, Node.js 大家都定俗成的回函一般都是 callback (err, data, blahblah...) 的,第一都是,如果都是 null 或者是 undefined 的。但是以前也意,所以回函的也都是比的。

    控制器

    action/index.js

    是一些基控制器。

    exports.index

    粹的首示。

    exports.download

    文件下控制器。由代可知,首先取 token 和 code 。 token 是 URL 的有效性而 code 即提取了。

    期我了下 token :

    Javascript 1 if (!functions.verifyBlahblah (token )) { 2 resp.redirect (baseConfig.webroot ); 3 } 

    而 verifyBlahblah 函就在文件(https://github.com/XadillaX/public-file-house/blob/master/plugin/functions.js#L21)面。

    Javascript 1 exports.verifyBlahblah = function (blahblah ) { 2 var array = blahblah.split ("^"); 3 var time = array[array.length - 1]; 4 array.pop (); 5 6 var encoder = require ("smpEncoder"); 7 8 try { 9 var text = encoder.norBack (array, time.toString ()); 10 text = encoder.decode (text ); 11 } catch (e ) { 12 return false; 13 } 14 15 var now = text.substr (0, 10 ); 16 var token = text.substr (10 ); 17 18 if (parseInt (Date.now () / 1000 ) - parseInt (now ) > 300 ) return false; 19 if (token !== require ("../commonConst").token ) return false; 20 21 return true; 22 }; 

    大意思就是把其打散到面,其中戳是最後一位。然後解密。最後解密後的 token 是否等於系的 token 以及戳有有期。

    大家通截取 Chrome 或者 Firefox 的求信息,不有地址:

    1 Request URL:http://localhost/download?file=662ZE&token=65^97^74^68^106^125^88^115^65^96^66^105^127^114^87^123^123^114^84^124^114^125^120^121^99^116^100^118^116^98^124^120^109^98^120^100^80^119^120^87^119^105^116^8^1395904110 2 Request Method:GET 3 Status Code:200 OK 

    而一坨 65^97^74^68^106^125^88^115^65^96^66^105^127^114^87^123^123^114^84...^1395904110 便是所的 token 了。而且本就是 demo , token 也就是便做做子了。

    接下去通之後,便可以中取文件信息了。如果有文件,那通 resp.download 函呈用。

    Javascript 1 var fileModel = new FileModel (); 2 fileModel.get (code, function (status, error, obj ) { 3 if (error ) resp.redirect (baseConfig.webroot ); 4 else { 5 if (obj === null ) { 6 resp.redirect (baseConfig.webroot + "/get/" + code + "/not-exist"); 7 } else { 8 resp.download (baseConfig.uploadDir + code, require ("urlencode")(obj.filename )); 9 } 10 } 11 }); 

    exports.getToken

    函就是生一有效的 token 用的。在前端是通 ajax 取的。

    Javascript 1 var encoder = require ("smpEncoder"); 2 var token = baseConfig.token; 3 var now = parseInt (Date.now () / 1000 ); 4 var result = encoder.encode (now + token ); 5 result = encoder.norGo (result, now.toString ()); 6 var resultString = ""; 7 for (var i = 0; i < result.length; i++) resultString += (result[i] + "^"); 

    大呢就是根目前的戳和系 token 一起加密生一有效的 token 。

    exports.send2fetion

    通自己的信自己送提取以忘。

    的用了一 fetion-sender 的模。 Repo 在(https://github.com/XadillaX/fetion-sender)。

    action/upload.js

    文件面其就一 exports.upload 函,另一是生成提取用的。

    function genAlphaKey (time, callback )

    生成提取。我假最多 10 次,若 10 次有生成唯一的就出用重。所以就有了:

    Javascript 1 function genAlphaKey (time, callback ) { 2 var keyLength = config.uploadLen; 3 var filename = alphaRandomer.rand (keyLength ); 4 var fileModel = new FileModel (); 5 6 fileModel.keyExists (filename, function (status, result ) { 7 if (!status ) { 8 if (time < maxTryTime ) { 9 genAlphaKey (time + 1, callback ); 10 } 11 else { 12 callback (false, result, ""); 13 } 14 15 return; 16 } else { 17 if (result ) genAlphaKey (time, callback ); 18 else { 19 callback (true, "", filename ); 20 } 21 } 22 }); 23 } 

    不地生成定的提取,然後通模型的 keyExists 函定提取是否存在,如果存在了就用重新生成,否就直接回。

    exports.upload

    上文件的面了。

    Javascript 1 if (req.files.files.length !== 1 ) { 2 result.status = false; 3 result.msg = "用正的姿我文件。"; 4 resp.send (200, result ); 5 return; 6 } 7 8 var fileInfo = req.files.files[0]; 9 if (fileInfo.size > config.maxUploadSize ) { 10 result.status = false; 11 result.msg = "文件太大啦,公所一次只能吃 10M 的文件哦。"; 12 resp.send (200, result ); 13 return; 14 } 

    前面一堆大致就是做下有效性判而已。然後用函生成有效的提取:

    Javascript 1 genAlphaKey (1, function (status, msg, filename ) { 2 ... 3 }); 

    如果生成成功的就往中添加文件信息:

    Javascript 1 var fileModel = new FileModel (); 2 fileModel.addFile (filename, 3 fileInfo.name, 4 fileInfo.headers["content-type"], 5 function (status, msg ) { 6 ... 7 } 8 ); 

    如果添加也成功了的,那把上到文件的文件移到上文件存目中,以便以後可以被下:

    Javascript 1 fs.rename (fileInfo.path, uploadDir + filename, function (err ) { 2 ... 3 }); 

    如果移也成功了的,那返回一成功的 json 信息:

    Javascript 1 result.status = true; 2 result.code = filename; 3 resp.send (200, result ); 

    就一 index.ejs 。然後通 backbone.js 用不同的模板和的似於 SPA (Solus Par Agula ) (Single Page Application ) 的效果。

    views/index/index.ejs

    像似於下面的就是 backbone.js 的模板概了:

    --- 未完 ---

    查看完整文章请访问:http://t.cn/RytTUeA

    更多技术类专题请关注 UPYUN 微信公众号

    欢迎转载,但请标明作者并保留原文出处,谢谢。

    4 条回复    2015-09-15 10:00:04 +08:00
    Septembers
        1
    Septembers  
       2015-09-14 16:34:55 +08:00 via Android
    勿全文 CC @Livid
    Livid
        2
    Livid  
    MOD
    PRO
       2015-09-14 16:37:11 +08:00
    @lock522 你是 UPYUN 的工作人员么?
    lock522
        3
    lock522  
    OP
       2015-09-14 16:38:44 +08:00
    @Livid 是的,我是负责线上这一块的,这篇稿件是内部投稿。
    Darkholme
        4
    Darkholme  
       2015-09-15 10:00:04 +08:00
    繁体看着有点累...
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     1219 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 114ms UTC 23:36 PVG 07:36 LAX 16:36 JFK 19:36
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86