Appearance
js
const fs = require('fs').promises
const http = require('http')
const path = require('path')
const mime = require('mime')
const urlParse = require('url')
const { createReadStream } = require('fs')
class StaticServer {
start (port, cb) {
// http.createServer() 回调的 this 指向创造的实例,需要将 this 指向
// StaticServer 实例
const server = http.createServer((req, res) => this.handleRequest(req, res))
server.listen(port, () => {
cb(port)
})
server.on('error', err => {
if (err.code === 'EADDRINUSE') {
server.listen(++port)
}
})
}
async handleRequest (req, res) {
const { pathname } = urlParse.parse(req.url, true)
// pathname 会出现 /,直接 resolve 结果是根路径下的 pathname
let filePath = path.join(`${ __dirname }/dist`, pathname)
try {
const stat = await fs.stat(filePath)
if (stat.isFile()) {
// 内部用一个对象保存所有后缀对应的类型
res.setHeader('Content-Type', `${ mime.getType(filePath) };charset=utf-8`)
// 可读流.pipe(可写流)
createReadStream(filePath).pipe(res)
// const data = await fs.readFile(filePath)
// res.end(data)
} else {
// 文件夹
filePath = path.join(filePath, 'index.html')
// 判断文件是否可以访问,是异步的,不存在时报错。同步用 fs.existSync
await fs.access(filePath)
res.setHeader('Content-Type', 'text/html;charset=utf-8')
createReadStream(filePath).pipe(res)
}
} catch (e) {
// 浏览器看心情请求 favicon.ico 图标
this.sendError(e, res)
}
}
sendError (e, res) {
res.statusCode = 400
res.end('Not Found')
}
}
const scheme = 'http',
host = '127.0.0.1',
port = 3000
const staticServer = new StaticServer()
staticServer.start(port, (_port) => {
console.log(`server running: ${ scheme }://${ host }:${ _port }`)
})