You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Node.js将URL中的图片存储到服务器文件夹

问题修复与正确实现

常见失败原因排查

你原本的流传输思路完全正确,不需要先下载到本地临时文件,直接通过管道流转存即可,操作失败基本是以下几个常见问题:

  • node-fetch@3.x版本返回的response.body是WHATWG标准的Web Stream,和Node.js原生Stream不兼容,直接传入pipeline会报错
  • 写入路径用相对路径时,是相对于Node进程启动的工作目录,而非脚本所在目录,容易出现目录不存在、无权限的问题
  • 部分图片源站会校验请求头的User-Agent、Referer等字段,直接请求会返回403/404错误

修复后的实现代码

方案1:适配node-fetch v3版本

需要先把Web Stream转成Node.js原生Stream再走管道:

import { createWriteStream, existsSync, mkdirSync } from 'fs';
import { pipeline } from 'stream';
import { promisify } from 'util';
import fetch from 'node-fetch';
// 引入Web转Node Stream的工具方法
import { Readable } from 'stream/web';
import { dirname } from 'path';

const streamPipeline = promisify(pipeline);

async function saveImageFromUrl(url, savePath) {
  // 提前创建存储目录,避免目录不存在报错
  const saveDir = dirname(savePath);
  if (!existsSync(saveDir)) {
    mkdirSync(saveDir, { recursive: true });
  }

  const response = await fetch(url, {
    // 可选:加请求头绕过源站校验,根据实际情况调整
    headers: {
      'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36'
    }
  });
  if (!response.ok) throw new Error(`请求失败: ${response.status} ${response.statusText}`);
  // Web Stream转Node.js可读流
  const nodeReadable = Readable.fromWeb(response.body);
  await streamPipeline(nodeReadable, createWriteStream(savePath));
  console.log('图片保存成功');
}

// 调用示例,用绝对路径避免相对路径的问题
// 用import.meta.url定位脚本所在目录,避免工作目录变动导致路径错误
const savePath = new URL('./img.png', import.meta.url).pathname;
saveImageFromUrl('http://dummy.com/5.png', savePath).catch(console.error);

方案2:用Node.js原生fetch(推荐,Node.js 18+版本支持)

不需要安装任何第三方依赖,原生返回的响应体已经做了适配,可以直接使用:

import { createWriteStream, existsSync, mkdirSync } from 'fs';
import { pipeline } from 'stream/promises'; // Node.js 16+版本已经内置promise化的pipeline,不用自己转
import { dirname } from 'path';

async function saveImageFromUrl(url, savePath) {
  const saveDir = dirname(savePath);
  if (!existsSync(saveDir)) {
    mkdirSync(saveDir, { recursive: true });
  }

  const response = await fetch(url);
  if (!response.ok) throw new Error(`请求失败: ${response.status} ${response.statusText}`);
  await pipeline(response.body, createWriteStream(savePath));
  console.log('图片保存成功');
}

const savePath = new URL('./img.png', import.meta.url).pathname;
saveImageFromUrl('http://dummy.com/5.png', savePath).catch(console.error);

额外注意事项

  • 生产环境建议给fetch请求加超时控制,避免请求长时间挂起占用服务器资源
  • 大文件传输可以通过在请求头加Range字段实现分片下载、断点续传
  • 存储文件前可以校验响应头的content-type字段,确认返回的是图片资源,避免存到错误的HTML错误页内容

内容的提问来源于stack exchange,提问作者Mayur Kukadiya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.04 09:27:02