foreword(序言)
前段天数在看T5450天数的“nodejs 合作开发两栖作战”,里头单纯如是说了两个 npm 包——httpserver(https://github.com/bahamas10/node-httpserver#readme),它能为他们构筑两个邻近地区动态天然资源服务项目器。透过 js,它是怎么做的呢,秉持疑惑的态度,我点进 github 查阅了它的源标识符,辨认出多于 100 二百一十三标识符因此,因此有了这篇文章。
在这首诗中,我想做的是将 httpserver 的源标识符展开回收,并做单纯的预测。
httpserver
1.概述
httpserver 究竟是个什么样的小东西呢?
译者是这种来论述的:
command line HTTP server tool for serving up local files, similar to python -m SimpleHTTPServer.(httpserver 是两个用作构筑邻近地区动态天然资源服务项目的实用性文档辅助工具,它和“python -m SimpleHTTPServer”类似于)
具体内容详尽的用语这儿就不做太多的如是说了,单纯讲:
它是两个实用性文档辅助工具;透过在适当的动态天然资源产品目录下输出单纯的指示(如:httpserver)方可构筑两个动态天然资源服务项目,预设透过http://0.0.0.0:8080/出访产品目录下的天然资源(预设为 index.html 或 index.htm,不然显示产品目录内部结构); 它有下列的缺点:采用单纯;可实用性;安全可靠;简化,大部份标识符只在两个文档中;可导出的,能 json 的内部结构展现产品目录内部结构;国际标准的 http:允诺Sonbhadra回到国际标准的 Mime types 和 Caching headers;2.npm 包内部结构
在写作源标识符以后,先介绍呵呵整座 npm 包的内部结构:
—manifest.xml
httpserver.js
package.json
内部结构非常单纯,全部的标识符都写在 httpserver.js 中,manifest.xml 文档在写作完之后辨认出它是没用的。
3.依赖包
在写作源标识符以后,我觉得首先介绍下源标识符中有所依赖的包会比较好。
“dependencies”: {
“access-log”: “~0.3.9”,
“static-route”: “~0.1.2”,
“posix-getopt”: “~1.2.0”,
“latest”: “~0.2.0”
}
他们辨认出有这几个包,它们大致的作用如下:
e(安全可靠的回到动态天然资源,具体内容之后再看)posix-getopt(导出实用性文档参数)latest(对依赖包展开检查更新)4.源标识符
标识符写作起来也是比较单纯的,主要能分为 2 个部分:参数条件执行部分、服务项目构筑部分。
var options = [
d(disable-index),
h(help),
H:(host),
n(no-indexes),
p:(port),
u(updates),
v(version)
].join();
var parser = new getopt.BasicParser(options, process.argv);
var opts = {
disableindex: process.env.HTTPSERVER_NO_INDEX,
host: process.env.HTTPSERVER_HOST || process.env.NODE_HOST,
nodir: process.env.HTTPSERVER_NO_DIR_LISTING,
port: process.env.HTTPSERVER_PORT || process.env.NODE_PORT,
};
var option;
while ((option = parser.getopt()) !== undefined) {
switch (option.option) {
case d: opts.disableindex = true; break;
case h: console.log(usage()); process.exit(0);
case H: opts.host = option.optarg; break;
case n: opts.nodir = true; break;
case p: opts.port = option.optarg; break;
case u: // check for updates
require(latest).checkupdate(package, function(ret, msg) {
console.log(msg);
process.exit(ret);
});
return;
case v: console.log(package.version); process.exit(0);
default: console.error(usage()); process.exit(1); break;
}
}
源标识符的核心部分也就是他们的服务项目构筑,最主要的是下面的 3 段标识符:
var staticroute = require(static-route)(
{
autoindex: !opts.nodir,
logger: function() {},
tryfiles: opts.disableindex ? [] : [index.html, index.htm]
}
);
function onrequest(req, res) {
accesslog(req, res);
staticroute(req, res);
}
http.createServer(onrequest).listen(opts.port, opts.host, listening);
ticroute 这个方法中,它调用了 static-route 这个 npm 包。
因此为了介绍 httpserver 具体内容的工作原理,还得好好写作下 static-route 的源标识符。
static-route
和 httpserver 是同两个译者,github 地址为:https://github.com/bahamas10/node-static-route#readme。
A route for an http server to safely serve static files.(它是两个 node 服务项目的路由,为服务项目安全可靠地回到动态文档天然资源)
具体内容的采用细节就不多说了,写作完源标识符自然就知道了。
源标识符有 200 二百一十三,我就不贴了,接下来直接回收预测。
1.源标识符输出的是两个方法,方法中回到了两个 staticroute 的方法,也就是他们上面用到的那个 staticroute 方法,所下列面对这个方法展开回收;
var parsed = url.parse(req.url, true);
// copy the array
var tryfiles = opts.tryfiles.slice(0);
// decode everything, and then fight against dir traversal
var reqfile;
try {
reqfile = path.normalize(decodeURIComponent(parsed.pathname));
} catch (e) {
res.statusCode = 400;
res.end();
return;
}
// slice off opts.slice
if (opts.slice && reqfile.indexOf(opts.slice) === 0)
reqfile = reqfile.substr(opts.slice.length);
3.判断允诺的 method,目前仅支持 HEAD 和 GET,其他允诺不支持则会回到 501 的状态码(501: Not Implemented,服务项目器不支持允诺的功能,无法完成允诺)
// unsupported methods
if ([HEAD, GET].indexOf(req.method) === -1) {
res.statusCode = 501;
res.end();
return;
}
4.拼接完整文档产品目录
var f = path.join((opts.dir || process.cwd()), reqfile);
5.接着执行两个 tryfiles 的方法,针对不存在的产品目录或文档、存在的产品目录、存在的文档展开不同的操作。这部分由于不好拆分,因此在标识符中做了适当的注释:
function tryfile() {
var file = path.join(f, tryfiles.pop());
// the user wants some actual data
fs.stat(file, function (err, stats) {
if (err) {
logger(err.message);
if (tryfiles.length) // 不断从预设的出访文档文档名数组中取文T) ? 404 : 500; // 判断错误原因,如果错误码是ENOENT(个人比较喜欢理解成Error NO Entity,即no such file or directory),则将状态码设置成,则判断是否是两个产品目录director(页面显示文档产品目录),或者是两个文档,则将文档读取出来
if (stats.isDirectory()) {
// directory
// forbidden
if (!opts.autoindex) { // 如果出访的是两个路径,并且httpserver实用性了–no-dir-listing,则回到403,即禁止出访产品目录
res.statusCode = 403;
res.end();
return;
}
// json stringify the dir
statall(file, function (e, files) {
if (e) {
logger(e.message);
res.statusCode = 500;
res.end();
return;
}
files = files.map(function (_file) { // 过滤列表中的产品目录
return _file.filename + (_file.directory ? / : );
});
files.sort(function (a, b) { // 产品目录排序,优先展现文档,其次按照大小排序
a = a.toLowerCase();
b = b.toLowerCase();
var adir = a.indexOf(/) > -1;
var bdir = b.indexOf(/) > -1;
if (adir && !bdir)
return -1;
else if (bdir && !adir)
return 1;
return a < b ? -1 : 1;
});
if (hap(parsed.query, json)) { // 如果允诺中加了参数json,则将files转成json格式并输出
res.setHeader(Content-Type, application/json; charset=utf-8);
res.write(JSON.stringify(files));
} else { // 不然以html的形式输出
res.setHeader(Content-Type, text/html; charset=utf-8);
writehtml(res, parsed.pathname, files);
}
res.end();
});
} else { // 如果出访的是两个文档则,直接回到文档流
streamfile(file, stats, req, res);
}
});
}
6.上面标识符中针对不同的情况调用了 3 个不同的方法:
streamfile:实用性必要的响应头信息,并以文档流的形式输出;stat图例
最后,整了一份单纯的图例来总结 httpserver 中涉及到的某些关系:
last(最后)
非常感谢您能写作完这首诗,您的写作是我不断前进的动力。
对于上面所述,有什么新的观点或辨认出有什么错误,希望您能指出。
最后,附上个人常逛的社交平台:
知乎:https://www.zhihu.com/people/bi-an-yao-91/activities csdn:https://blog.csdn.net/YaoDeBiAn github: https://github.com/yaodebian
我的邮箱:[email protected]、[email protected]
个人目前能力有限,并没有自主构筑两个社区的能力,如有任何问题或想法与我沟通,请透过上述某个平台联系我,谢谢!!!