gzy-server
v1.0.1
Published
#### 初始化文件夹 ``` npm init -y ```
Downloads
2
Readme
模拟http-server 实现自己的一个服务工具
初始化文件夹
npm init -y
在package.json中添加
"bin":{
"gzy-server":"./bin/www.js"
}
创建命令指定的目录及文件,并且制定运行环境
13.cli/bin/www.js
#! /usr/bin/env node
npm link 把当前这个包链接到npm中
// /Documents/webstorm/Project/blog/13.cli
npm link
安装commander命令行工具以及chalk粉笔工具
yarn add commander chalk --save
根据commander API 对你的工具设置个性化提示
// 这个argv最后返回的就是一个对象,是根据你命令执行的后面的参数决定的
let argv = commander
.version(version,'-v, --version') // 设置版本号
.usage('[options] <gzy-server --port 3000>') // 用例设置
.option('-p, --port <n>','server port')
.option('-a, --address <n>', 'server address')
.option('-d, --dir <n>', 'server show list')
commander
.command('log') // 这三个组成一个动作
.option('--log','console.log')
.action(function(){
console.log('hello')
})
commander
.on('--help', function(){
console.log('')
console.log('gzy-server:');
console.log(' $ custom-help --help');
console.log(' $ custom-help -h');
})
.parse(process.argv);
设置默认配置
// 如果执行命令传入了参数以参数为准
let config = Object.assign({
dir:process.cwd(),
address:'localhost',
port:8080
},argv)
根据默认配置启动一个服务
// 写一个创建server的功能
let Server = require('../src/server.js')
let server = new Server(config); // 自己定义了一个启动服务的类
server.start(); // 定义了一个start方法,start()相当于http.createServer()
开始写Server类
定义实例上的属性
let tmplStr = fs.readFileSync(path.join(__dirname,'template.html'),
'utf8');
class Server {
constructor(config) {
this.port = config.port; // 端口号
this.address = config.address; // eg:localhost
this.dir = config.dir; // dir表示当前启动的目录 / 手动指定的
this.tmpl = tmplStr; // 如果是目录的话渲染的template模版
}
}
start (启动服务)
start() {
let server = http.createServer(this.handleRequest());
server.listen(this.port, this.address, () => {
console.log(chalk.yellow(`Starting up http-server, serving ./
Available on:`
));
console.log(` http://${this.address}:${chalk.green(this.port)}`)
});
}
handleRequest (处理请求)
handleRequest() { // 处理请求的方法
return async (req, res) => {
// 需要判断当前请求的内容是文件还是文件
let { pathname } = url.parse(req.url);
pathname = decodeURI(pathname); // 文件名为汉字找不到
if(pathname === '/favicon.ico') return this.sendError('找不到');
let realPath = path.join(this.dir, pathname);
try {
let statObj = await fs.stat(realPath);
if (statObj.isFile()) { // 文件操作
this.sendFile(req, res, realPath, statObj);
} else { // 目录操作
let dirs = await fs.readdir(realPath);// ['www.js']
// 渲染出一个渲染后的字符串
// dirs应该包含 当前点击的链接 和显示的路径
dirs = dirs.map((dir)=>{
return {url:path.join(pathname,dir),dir}
})
let renderStr = ejs.render(this.tmpl, { dirs});
res.setHeader('Content-Type','text/html;charset=utf8');
res.end(renderStr);
}
} catch (e) {
this.sendError(e,res);
}
}
}
sendError (处理错误)
sendError(e,res) {
console.log(e);
res.statusCode = 404;
res.end(`Not found`);
}
sendFile (处理文件)
sendFile(req,res,path,statObj){
// range (需要放到上面,先走分段)
if(this.range(req,res,path,statObj)) return;
// 先判断有没有缓存 有缓存 走缓存 boolean
if (this.cache(req, res, path, statObj)){
return res.statusCode = 304, res.end();
}
// gzip压缩 转化流
// Accept-Encoding: gzip, deflate, br
res.setHeader('Content-Type', mime.getType(path) + ';charset=utf-8');
// 返回的文件需要压缩
let zip;
if (zip = this.gzip(req,res)){ // 调用方法后返回的是一个转化流
return fs.createReadStream(path).pipe(zip).pipe(res);
}
fs.createReadStream(path).pipe(res);
}
range (分段请求)
range(req,res,path,statObj){
let range = req.headers['range'];
if(range){
let [,start,end] = range.match(/(\d*)-(\d*)/);
start = start ? Number(start):0;
end = end ? Number(end):statObj.size;
res.statusCode = 206;
res.setHeader('Content-Range',`bytes=${start}-${end}/${statObj.size}`);
res.setHeader('Content-Length',end-start+1);
fs.createReadStream(path,{start,end}).pipe(res);
return true;
}else{
return false
}
}
cache (缓存)
cache(path,statObj,req,res){
res.setHeader('Cache-Control','Max-Age=10');
res.setHeader('Expries',new Date(Date.now()+10*1000).toLocaleString());
let ctime = statObj.ctime.toLocaleString();
let etag = ctime+'_'+statObj.size;
res.setHeader('Last-Modified',ctime);
res.setHeader('Etag',etag)
let ifModifiedSince = req.headers['if-modified-since'];
let ifNoneMatch = req.headers['if-none-match'];
if(ifModifiedSince && ifNoneMatch ){
if(ifModifiedSince === ctime && ifNoneMatch === etag){
res.setHeader('Content-Encoding','gzip');
return zlib.createGzip();
}else{
res.setHeader('Content-Encoding','gzip');
return zlib.createDeflate();
}
}else{
return false
}
}
gzip (压缩)
gzip(req,res){
let encoding = req.headers['accept-encoding'];
if(encoding.includes('gzip')){
res.setHeader('Content-Encoding','gzip');
return zlib.createGzip();
}
if(encoding.includes('deflate')){
res.setHeader('Content-Encoding','deflate');
return zlib.createDeflate();
}
return false;
}
先切换到官方的源
nrm use npm
添加用户(没有的话是注册)
npm addUser
发布
npm publish