在 Node.js 中使用 axios 配置代理并实现图片并发下载

avatar
作者
猴君
阅读量: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,函数会提取文件名称进行路径的拼接,如果路径不存在则会自动创建。

三、参考资料

广告一刻

为您即时展示最新活动产品广告消息,让您随时掌握产品活动新动态!