| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354 |
- /**
- * 根据 url 下载文件到 savePath(支持 http/https)
- * 入参:url, savePath(相对路径时基于 folderPath)
- */
- const path = require('path')
- const fs = require('fs')
- const https = require('https')
- const http = require('http')
- function buildSavePath(savePath, folderPath) {
- if (!savePath || typeof savePath !== 'string') return null
- const trimmed = savePath.trim()
- if (path.isAbsolute(trimmed) || trimmed.match(/^[A-Za-z]:/)) return trimmed
- return folderPath ? path.join(folderPath, trimmed) : path.resolve(trimmed)
- }
- function downloadToFile(url, filePath) {
- return new Promise((resolve, reject) => {
- const protocol = url.startsWith('https') ? https : http
- const request = protocol.get(url, { timeout: 60000 }, (response) => {
- if (response.statusCode === 301 || response.statusCode === 302) {
- const redirect = response.headers.location
- if (redirect) return downloadToFile(redirect, filePath).then(resolve).catch(reject)
- }
- if (response.statusCode !== 200) {
- reject(new Error(`HTTP ${response.statusCode}`))
- return
- }
- const dir = path.dirname(filePath)
- if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true })
- const file = fs.createWriteStream(filePath)
- response.pipe(file)
- file.on('finish', () => { file.close(); resolve({ success: true, path: filePath }) })
- file.on('error', (err) => { fs.unlink(filePath, () => {}); reject(err) })
- })
- request.on('error', reject)
- request.setTimeout(60000, () => { request.destroy(); reject(new Error('timeout')) })
- })
- }
- async function executeDownload({ url, savePath, folderPath }) {
- if (!url || typeof url !== 'string' || !url.trim()) return { success: false, error: 'download 缺少 url 参数' }
- if (!savePath && savePath !== '') return { success: false, error: 'download 缺少 savePath 参数' }
- const absolutePath = buildSavePath(String(savePath).trim(), folderPath)
- if (!absolutePath) return { success: false, error: 'download 缺少 savePath 参数' }
- try {
- await downloadToFile(url.trim(), absolutePath)
- return { success: true, path: absolutePath }
- } catch (e) {
- return { success: false, error: e && (e.message || String(e)) || 'download failed' }
- }
- }
- module.exports = { executeDownload }
|