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

news/2024/8/26 10:17:20 标签: axios, node.js, 学习, 笔记

文章目录

      • 一、创建 Axios 实例
      • 二、图片并发下载
      • 三、参考资料

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

三、参考资料

  • https://www.npmjs.com/package/p-limit
  • https://www.bright.cn/blog/how-tos/axios-proxy
  • https://www.jianshu.com/p/8021d8851775

http://www.niftyadmin.cn/n/5558043.html

相关文章

使用milvus-sdk-go的迭代器导出数据

使用milvus-sdk-go的迭代器导出数据 迭代器是一种功能强大的工具,可帮助您使用主键值和布尔表达式迭代集合中的大量数据或所有数据。这可以显著改善您检索数据的方式。与传统的offset和limit参数用法不同,后者可能会随着时间的推移而变得效率低下&#…

Java面试八股之Redis Stream的实现原理及应用场景

Redis Stream的实现原理及应用场景 Redis Stream是一种在Redis 5.0版本中引入的数据结构,它主要用于实现高效的消息队列服务。下面我将详细解释其实现原理以及一些常见的应用场景。 实现原理 1. 结构组成: - Redis Stream由一个或多个消息组成&#xf…

CSS3 transform rotate(旋转)锯齿/元素抖动模糊的解决办法

要解决CSS3 transform rotate(旋转)锯齿/元素抖动模糊的问题,可以尝试以下方法: 使用硬件加速 为元素添加transform: translateZ(0);或者will-change: transform;属性,以启用硬件加速,提高渲染性能。 .elem…

一键发布:抖音短视频矩阵系统批量上传与智能混剪功能解析

在数字化时代,抖音短视频已经成为人们日常生活中不可或缺的一部分。无论是记录生活点滴,还是展示个人才华,抖音都为我们提供了一个广阔的舞台。然而,对于内容创作者来说,如何高效、便捷地发布短视频,实现内…

安卓自带camera hal3 实例README.md翻译

最近,遇到一个这样的问题,临时了解下这个驱动实现架构和特点,翻译如下 V4L2相机HALv3 camera.v4l2库使用视频Linux 2(V4L2)接口实现了camera HAL v3。这使得它在理论上可以与各种设备配合使用,尽管V4L2的…

自定义列表标记(dl-dt-dd)

dl:自定义列表容器标记dt:列表标题dd:列表内容 目录 例子 常用语网页的footer&#xff0c;例如 例子 <!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthde…

套用BI方案做数据可视化是种什么体验?

在数字化转型的浪潮中&#xff0c;数据可视化作为连接数据与决策的桥梁&#xff0c;其重要性日益凸显。近期&#xff0c;我有幸体验了奥威BI方案进行数据可视化的全过程&#xff0c;这不仅是一次技术上的探索&#xff0c;更是一次对高效、智能数据分析的深刻感受。 初识奥威&a…

待机电流过大

问题&#xff1a; 待机电流过大&#xff0c;有10几mA 原因&#xff1a; 漏电&#xff0c;芯片引脚没有关闭 验证过程&#xff1a; 对照原理图&#xff0c;把芯片几乎所有的管脚全部关掉。 比如LED管脚设置为输出模式&#xff0c;输出0 PWM管脚设置为输出模式&#xff0c…