diff --git a/package.json b/package.json index ef4378f..df04623 100644 --- a/package.json +++ b/package.json @@ -8,7 +8,8 @@ "dev": "cross-env NODE_ENV=development nodemon --exec tsx src/index.ts", "build": "rimraf dist && rollup -c", "deploy": "rsync -avz dist/ light:~/apps/var-proxy/backend", - "reload": "ssh light pm2 restart proxy" + "reload": "ssh light pm2 restart proxy", + "pub": "npm run build && npm run deploy && npm run reload" }, "keywords": [], "author": "", diff --git a/src/module/get-content-type.ts b/src/module/get-content-type.ts index 9289e60..5dc1806 100644 --- a/src/module/get-content-type.ts +++ b/src/module/get-content-type.ts @@ -3,17 +3,47 @@ import path from 'path'; export const getContentType = (filePath: string) => { const extname = path.extname(filePath); const contentType = { - '.txt': 'text/plain', - '.html': 'text/html', - '.js': 'text/javascript', - '.css': 'text/css', - '.json': 'application/json', + '.html': 'text/html; charset=utf-8', + '.js': 'text/javascript; charset=utf-8', + '.css': 'text/css; charset=utf-8', + '.txt': 'text/plain; charset=utf-8', + '.json': 'application/json; charset=utf-8', '.png': 'image/png', '.jpg': 'image/jpg', '.gif': 'image/gif', '.svg': 'image/svg+xml', '.wav': 'audio/wav', '.mp4': 'video/mp4', + '.md': 'text/markdown; charset=utf-8', // utf-8配置 + '.ico': 'image/x-icon', // Favicon 图标 + '.webp': 'image/webp', // WebP 图像格式 + '.webm': 'video/webm', // WebM 视频格式 + '.ogg': 'audio/ogg', // Ogg 音频格式 + '.mp3': 'audio/mpeg', // MP3 音频格式 + '.m4a': 'audio/mp4', // M4A 音频格式 + '.m3u8': 'application/vnd.apple.mpegurl', // HLS 播放列表 + '.ts': 'video/mp2t', // MPEG Transport Stream + '.pdf': 'application/pdf', // PDF 文档 + '.doc': 'application/msword', // Word 文档 + '.docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document', // Word 文档 (新版) + '.ppt': 'application/vnd.ms-powerpoint', // PowerPoint 演示文稿 + '.pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation', // PowerPoint (新版) + '.xls': 'application/vnd.ms-excel', // Excel 表格 + '.xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet', // Excel 表格 (新版) + '.csv': 'text/csv; charset=utf-8', // CSV 文件 + '.xml': 'application/xml; charset=utf-8', // XML 文件 + '.rtf': 'application/rtf', // RTF 文本文件 + '.eot': 'application/vnd.ms-fontobject', // Embedded OpenType 字体 + '.ttf': 'font/ttf', // TrueType 字体 + '.woff': 'font/woff', // Web Open Font Format 1.0 + '.woff2': 'font/woff2', // Web Open Font Format 2.0 + '.otf': 'font/otf', // OpenType 字体 + '.wasm': 'application/wasm', // WebAssembly 文件 + '.pem': 'application/x-pem-file', // PEM 证书文件 + '.crt': 'application/x-x509-ca-cert', // CRT 证书文件 + '.yaml': 'application/x-yaml; charset=utf-8', // YAML 文件 + '.yml': 'application/x-yaml; charset=utf-8', // YAML 文件(别名) + '.zip': 'application/octet-stream', }; return contentType[extname] || 'application/octet-stream'; }; diff --git a/src/module/index.ts b/src/module/index.ts index e1af253..ccb79c7 100644 --- a/src/module/index.ts +++ b/src/module/index.ts @@ -163,8 +163,15 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR const [indexFilePath, etag] = indexFile.split('||'); const contentType = getContentType(indexFilePath); const isHTML = contentType.includes('html'); + // 如果 content是 'application/octet-stream' 会下载文件, 添加文件后缀 + if (contentType === 'application/octet-stream') { + // 提取文件名,只保留文件名而不是整个路径 + const fileName = path.basename(indexFilePath); + res.setHeader('Content-Disposition', `attachment; filename=${fileName}`); + } // 不存在的文件,返回indexFile的文件 res.writeHead(200, { 'Content-Type': contentType, 'Cache-Control': isHTML ? 'no-cache' : 'public, max-age=3600' }); + const filePath = path.join(fileStore, indexFilePath); const readStream = fs.createReadStream(filePath); readStream.pipe(res); @@ -180,6 +187,12 @@ export const handleRequest = async (req: http.IncomingMessage, res: http.ServerR const filePath = path.join(fileStore, appFilePath); let contentType = getContentType(filePath); const isHTML = contentType.includes('html'); + // 如果 content是 'application/octet-stream' 会下载文件, 添加文件后缀 + if (contentType === 'application/octet-stream') { + // 提取文件名,只保留文件名而不是整个路径 + const fileName = path.basename(appFilePath); + res.setHeader('Content-Disposition', `attachment; filename=${fileName}`); + } res.writeHead(200, { 'Content-Type': contentType, 'Cache-Control': isHTML ? 'no-cache' : 'public, max-age=3600', // 设置缓存时间为 1 小时