| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163 |
- //原生模块
- let http = require('http')
- let fs = require('fs')
- let path = require('path')
- let url = require('url')
- let { promisify, inspect } = require('util')
- let stat = promisify(fs.stat)
- let readdir = promisify(fs.readdir)
- let zlib = require('zlib')
- //第三方包
- let chalk = require('chalk')
- let mime = require('mime')
- let multiparty = require('multiparty')
- //自定义模块
- let config = require('./config.js')
- let compileHtml = require('./generater/compileHtml.js')
- let handleFile = require('./generater/handleFile.js')
- class Server {
- constructor(argv) {
- //挂载模版方法
- this.compileHtml = compileHtml()
- //挂在配置,处理默认值
- this.config = Object.assign({}, config, argv)
- }
- //启动http服务器
- 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}`;
- console.log(`${chalk.blue('server has started at')} ${chalk.green(url)}`);
- })
- }
- //http服务器请求处理函数
- async request(req, res) {
- //处理跨域
- let domain = 'http://' + req.headers['host']
- this.handleOption(req, res, domain)
- if (req.method == 'OPTIONS') {
- return res.end()
- }
- let { pathname } = url.parse(req.url)
- //读文件目录
- let filepath = path.join(this.config.document, pathname)
- //处理分块传输
- if (pathname == '/upfile' && req.method == 'POST') {
- return this.handleChunk(req, res, this.config.document)
- }
- //如果是文件夹,读取文件夹发送目录,不是文件夹返回文件内容
- try {
- let fileStat = await stat(filepath)
- if (fileStat.isDirectory()) {
- let files = await readdir(filepath)
- files = files.map(file => {
- return {
- name: file,
- url: path.join(pathname, file)
- }
- })
- this.sendDirectory(req, res, filepath, files)
- } else {
- let ifCatch = this.handleCatch(req, res, filepath, fileStat)
- //如果走缓存,则直接返回
- if (ifCatch) return
- this.sendFile(req, res, filepath)
- }
- } catch (err) {
- this.sendError(err, res)
- }
- }
- //处理断点续传
- handleChunk(req, res, filepath) {
- let form = new multiparty.Form();
- form.parse(req, function (err, fields, files) {
- if (err) {
- console.error('multiparty错误:', err)
- }
- if (files) {
- handleFile(req, res, fields, files, filepath)
- }
- });
- }
- //处理跨域等
- handleOption(req, res, domain) {
- //cors跨域
- res.setHeader('Access-Control-Allow-Origin', domain)
- res.setHeader('Access-Control-Allow-Credentials', true)
- res.setHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE,OPTIONS")
- res.setHeader("Access-Control-Allow-Headers", "Content-Type, Access-Control-Allow-Headers, Authorization, X-Requested-With,Range")
- }
- //缓存处理函数
- handleCatch(req, res, filepath, fileStat) {
- //强制缓存
- res.setHeader('Expries', new Date(Date.now() + 30 * 1000).toGMTString())
- res.setHeader('Catch-Control', 'private,max-age=30')
- //对比缓存
- let ifModifiedSince = req.headers['if-modified-since']
- let ifNoneMatch = req.headers['if-none-match']
- let lastModified = fileStat.ctime.toGMTString()
- let eTag = fileStat.size
- res.setHeader('Last-Modified', lastModified)
- res.setHeader('ETag', eTag)
- //任何一个对比缓存头不匹配,则不走缓存
- if (ifModifiedSince && ifModifiedSince != lastModified) {
- return false
- }
- if (ifNoneMatch && ifNoneMatch != eTag) {
- return false
- }
- //当请求中存在任何一个对比缓存头,则返回304,否则不走缓存
- if (ifModifiedSince || ifNoneMatch) {
- res.writeHead(304)
- res.end()
- return true
- } else {
- return false
- }
- }
- //发送文件夹目录
- sendDirectory(req, res, filepath, files) {
- res.setHeader('Content-Type', 'text/html')
- //用模版引擎编译模版,得到编译后的结果
- let html = this.compileHtml({ title: 'bin2', files })
- res.end(html)
- }
- //发送文件
- sendFile(req, res, filepath) {
- res.setHeader('Content-Type', mime.getType(filepath) + ';charset=utf-8')
- let readStream = fs.createReadStream(filepath)
- //处理压缩
- let zlibStream = this.handleZlib(req, res)
- if (zlibStream) {
- readStream.pipe(zlibStream).pipe(res)
- } else {
- readStream.pipe(res)
- }
- }
- //处理压缩
- handleZlib(req, res) {
- let acceptEncoding = req.headers['accept-encoding']
- if (/\bgzip\b/g.test(acceptEncoding)) {
- res.setHeader('Content-Encoding', 'gzip');
- return zlib.createGzip()
- } else if (/\bdeflate\b/g.test(acceptEncoding)) {
- res.setHeader('Content-Encoding', 'deflate');
- return zlib.createDeflate()
- } else {
- return null
- }
- }
- //错误处理函数
- sendError(err, res) {
- res.statusCode = 500;
- res.end(`${err.toString()}`);
- }
- }
- module.exports = Server
|