async request(req, res) { let { pathname } = url.parse(req.url); if (pathname == '/favicon.ico') { return this.sendError('not found', req, res); } let filepath = path.join(this.config.root, pathname); try { let statObj = await stat(filepath); if (statObj.isDirectory()) { let files = await readdir(filepath); files = files.map(file => ({ name: file, url: path.join(pathname, file) })); let html = this.list({ title: pathname, files }); res.setHeader('Content-Type', 'text/html'); res.end(html); } else { this.sendFile(req, res, filepath, statObj); } } catch (e) { debug(inspect(e)); this.sendError(e, req, res); } } sendFile(req, res, filepath, statObj) { if (this.handleCache(req, res, filepath, statObj)) return; res.setHeader('Content-Type', mime.getType(filepath) + ';charset=utf-8'); let encoding = this.getEncoding(req, res); let rs = this.getStream(req, res, filepath, statObj); if (encoding) { rs.pipe(encoding).pipe(res); } else { rs.pipe(res); } }
手写Node静态资源服务器的实现方法(6)
支持断点续传
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 }); }
支持对比缓存,通过etag的方式
handleCache(req, res, filepath, statObj) { let ifModifiedSince = req.headers['if-modified-since']; let isNoneMatch = req.headers['is-none-match']; res.setHeader('Cache-Control', 'private,max-age=30'); res.setHeader('Expires', new Date(Date.now() + 30 * 1000).toGMTString()); let etag = statObj.size; let lastModified = statObj.ctime.toGMTString(); res.setHeader('ETag', etag); res.setHeader('Last-Modified', lastModified); if (isNoneMatch && isNoneMatch != etag) { return fasle; } if (ifModifiedSince && ifModifiedSince != lastModified) { return fasle; } if (isNoneMatch || ifModifiedSince) { res.writeHead(304); res.end(); return true; } else { return false; } }
支持文件压缩
getEncoding(req, res) { let acceptEncoding = req.headers['accept-encoding']; if (/\bgzip\b/.test(acceptEncoding)) { res.setHeader('Content-Encoding', 'gzip'); return zlib.createGzip(); } else if (/\bdeflate\b/.test(acceptEncoding)) { res.setHeader('Content-Encoding', 'deflate'); return zlib.createDeflate(); } else { return null; } }
内容版权声明:除非注明,否则皆为本站原创文章。