-
Notifications
You must be signed in to change notification settings - Fork 0
/
appRange.js
117 lines (114 loc) · 4.22 KB
/
appRange.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//添加上服务器压缩+断点续传
const http = require('http')
const path = require('path')
const url = require('url')
const fs = require('fs')
const mime = require('mime')
var zlib = require('zlib');
let chalk = require('chalk');
process.env.DEBUG = 'static:app';
let debug = require('debug')('static:app');//每个debug实例都有一个名字,是否在控制台打印取决于环境变量中DEBUG的值是否等于static:app
const {promisify} = require('util')
let handlebars = require('handlebars');
const config = require('./config')
const stat = promisify(fs.stat)
const readDir = promisify(fs.readdir)
//获取编译模板
function getTemplet() {
let tmpl = fs.readFileSync(path.resolve(__dirname, 'template', 'list.html'), 'utf8');
return handlebars.compile(tmpl);
}
class Server {
constructor(argv) {
this.config = Object.assign({}, config, argv);
this.list = getTemplet()
}
//启动服务
start() {
let server = http.createServer();
server.on('request', this.request.bind(this))
server.listen(this.config.port);
let url=`http://${this.config.host}:${this.config.port}`;
debug(`静态服务启动成功${chalk.green(url)}`);
}
async request(req, res) {//服务监听函数
let pathName = url.parse(req.url).path;
let filePath = path.join(this.config.root, pathName);
if (filePath.indexOf('favicon.ico') > 0) {
this.sendError(req, res, 'not found',404);
return
}
try {//在静态服务文件夹存在访问的路径内容
let statObj = await stat(filePath);
if (statObj.isDirectory()) {//是文件夹
let directories = await readDir(filePath);
let files = directories.map(file => {
return {
filename: file,
url: path.join(pathName, file)
}
});
let htmls = this.list({
title: pathName,
files
});
res.setHeader('Content-Type', 'text/html');
res.end(htmls);
} else {//是文件
this.sendContent(req, res, filePath, statObj);
}
} catch (err) {//静态服务器不存在访问内容
this.sendError(req, res, err);
}
}
sendContent(req, res, filePath, statObj) {//向客户端响应内容
let fileType = mime.getType(filePath);
res.setHeader('Content-Type', `${fileType};charset=UTF-8`);
let enCoding=this.sourceGzip(req,res);
let rs = this.getStream(req,res,filePath,statObj);//获取文件的可读流
if(enCoding){//开启压缩传输模式
rs.pipe(enCoding).pipe(res);
}else{
rs.pipe(res);
}
}
sourceGzip(req,res){//资源开启压缩传输
// Accept-Encoding:gzip, deflate, sdch, br
let encoding=req.headers['accept-encoding'];
if(/\bgzip\b/.test(encoding)){//gzip压缩格式
res.setHeader('Content-Encoding','gzip');
return zlib.createGzip();
}else if(/\bdeflate\b/.test(encoding)){//deflate压缩格式
res.setHeader('Content-Encoding','deflate');
return zlib.createDeflate();
}else{
return null;
}
}
getStream(req,res,filePath,statObj) {//返回一个可读流
let start = 0;
let end = statObj.size - 1;
let range = req.headers['range'];
if (range) {//支持断点续传
res.setHeader('Accept-Range', 'bytes');
res.statusCode = 206;//返回整个内容的一块
let result = range.match(/bytes=(\d*)-(\d*)/);
if (result) {
start = isNaN(result[1]) ? start : parseInt(result[1]);
end = isNaN(result[2]) ? end : parseInt(result[2]) - 1;
}
}
return fs.createReadStream(filePath, {
start, end
});
}
sendError(req, res, err,errCode) {//发送错误
if(errCode){
res.statusCode=errCode;
}else{
res.statusCode = 500;
}
res.end(`${err.toString()}`)
}
}
module.exports = Server;