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

文章目录

一、创建 Axios 实例

可以创建一个 axiosConfig.ts 文件用于创建和更新相关实例:

js 复制代码
// 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
};

代理相关配置可以以字符串的方式先存储在数据库中,再根据需要读取和修改以实现动态更新代理配置:

js 复制代码
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 文件用来处理图片下载相关方法:

js 复制代码
// 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,函数会提取文件名称进行路径的拼接,如果路径不存在则会自动创建。

三、参考资料

相关推荐
每天都要写算法(努力版)14 分钟前
【行业前沿报告】DAgger:让智能体在自己走到的状态上学习
人工智能·学习·机器学习
91刘仁德3 小时前
HTTP协议详解:从URL到HTTP服务器的完整实战
服务器·网络·笔记·网络协议·http
sunshine22 girl4 小时前
Java学习六 Java常见API-2--String-3-字符串的截取替换和其他方法
java·开发语言·学习
sunshine22 girl5 小时前
Java学习六 Java常见API-1-Radom随机数
java·开发语言·学习
Answer1st5 小时前
【嵌入式学习】嵌入式原理知识-DMA(九)
学习
柳鲲鹏5 小时前
老电脑X99安装WIN11 26H2总结、问题解决办法汇总
笔记
传奇开心果编程6 小时前
【ArkUI进阶练中学】第11课:安全与合规进阶
学习·ui·华为·harmonyos
niyongsheng6 小时前
后端零改动,给若依换一套现代化前端
vue.js·开源·node.js
Mr_Macallon7 小时前
C++回顾(基础)(01)
c语言·开发语言·c++·学习
sunoo-2298 小时前
【ARM嵌入式学习笔记第十天】i.MX6ULL eLCDIF控制器驱动RGB LCD全解析(硬件原理+寄存器配置+裸机代码)
arm开发·笔记·学习