阅读量:0
文章目录
一、创建 Axios 实例
可以创建一个 axiosConfig.ts
文件用于创建和更新相关实例:
// server/utils/axiosConfig.ts const axios = require("axios"); const { HttpsProxyAgent } = require('https-proxy-agent'); // axios 实例 let axiosInstance = null; // 代理表单(可以从数据库读取相关配置) let proxyParams = { state: true, host: "127.0.0.1", port: 10809, protocol: "http", username: "", password: "" }; // 创建 axios 实例 const createAxiosInstance = () => { // 判断是否开启代理 const useProxy = proxyParams['state'] == true; let axiosConfig = { timeout: 5000 }; // 启用代理服务 if (useProxy && proxyParams) { const agent = new HttpsProxyAgent({ host: proxyParams.host, port: proxyParams.port, protocol: proxyParams.protocol, }); axiosConfig['httpsAgent'] = agent; } // 代理服务器 用户名、密码 if (useProxy && proxyParams['username'] && proxyParams['password']) { axiosConfig['auth'] = { username: proxyParams['username'], password: proxyParams['password'] }; } axiosInstance = axios.create(axiosConfig); } // 获取 Axios 实例 const getAxiosInstance = () => { if (!axiosInstance) { createAxiosInstance(); } return axiosInstance; } // 更新 Axios 实例 const updateAxiosInstance = () => { createAxiosInstance(); } module.exports = { getAxiosInstance, updateAxiosInstance };
代理相关配置可以以字符串的方式先存储在数据库中,再根据需要读取和修改以实现动态更新代理配置:
const { getSettingCache } = require("../db/SettingManager.ts"); const createAxiosInstance = () => { // 获取配置信息 const settingCache = getSettingCache(); // 判断是否开启代理 const proxyParams = settingCache["proxy"] ? JSON.parse(settingCache["proxy"]) : null; // { // proxy: '{"state":true,"host":"127.0.0.1","port":10809,"protocol":"http","username":"","password":""}', // } }
二、图片并发下载
此处使用 p-limit
来控制并发数量:
yarn add p-limit
创建一个 downloadImages.ts
文件用来处理图片下载相关方法:
// server/utils/downloadImages.ts const { getAxiosInstance } = require('../utils/axiosConfig.ts'); const path = require("path"); const fs = require("fs"); const downloadImagesByUrls = async (imageUrls, savePath) => { // 为避免出现循环导入,此处使用动态导入 const pLimit = (await import('p-limit')).default; // 提取 url 中的文件名 例:xxx.jpg const filenames = imageUrls.map((url) => path.basename(url)); // 判断是否存在目标文件夹,不存在则创建 if (!fs.existsSync(savePath)) { fs.mkdirSync(savePath, { recursive: true }); } // 下载单个图片的函数 const downloadImage = async (url, filename) => { // 拼接文件路径 const fullPath = path.join(savePath, filename); try { // 获取 axios 实例 const axiosInstance = await getAxiosInstance(); const response = await axiosInstance({ method: "get", url: url, responseType: "stream", }); const writer = await fs.createWriteStream(fullPath); // 用Promise包装stream完成事件 return new Promise((resolve, reject) => { response.data.pipe(writer); writer.on("finish", () => resolve({ filename, success: true })); writer.on("error", (err) => reject({ filename, success: false, error: err.message })); response.data.on("error", (err) => reject({ filename, success: false, error: err.message })); }); } catch (error) { return { filename, success: false, error: error.message }; } }; // 并发控制 const limit = pLimit(5); // 创建下载任务 const tasks = imageUrls.map((url, index) => limit(() => downloadImage(url, filenames[index])) ); // 执行下载任务并等待所有任务完成 const results = await Promise.all(tasks); return results; }; module.exports = { downloadImagesByUrls, };
代码说明: 该方法可直接复制使用,需要传递两个参数,imageUrls
参数为需要下载的图片列表,是一个存储了图片下载链接的数组,例:['http://xxx','http://xxx']
,第二个参数是 savePath
,即文件保存路径,例:D:/Desktop
,函数会提取文件名称进行路径的拼接,如果路径不存在则会自动创建。