一个前端,爱跑步、爱吉他、爱做饭、爱生活、爱编程、爱南芳姑娘,爱我所爱。世间最温暖又无价的是阳光、空气与爱,愿它们能带你去更远的地方。

  • 文章
  • 心情
  • 照片墙
  • 工具
  • 开发技术分享

    图片URL转file文件(前端+后端node.js)

    技术 1355 2022-08-26 19:20


    需求:

    主要是想自动化的根据图片url上传一张全新的图片到我们的服务器

    正常手动操作,就是需要把这个图片根据url 下载下来

    然后去手动的上传 然后上传成功。

    但是如果让脚本去执行这个操作呢?


    前端

    第一步:

    先把图片的url转为blob文件

    关键代码:  let imgFile = new File([blob], imageName, { type: "image/jpeg" });

        // 选择默认图片
        function chooseStaticImg(imageUrl) {
          getImageFileFromUrl(imageUrl, "图片.png", function (file) {
            // file = file; //获取file对象
            console.log(file);
          });
        }
        // 根据路径返回file
        function getImageFileFromUrl(url, imageName, callback) {
          fetch(url)
            .then((res) => {
              return res.blob();
            })
            .then((blob) => {
              let imgFile = new File([blob], imageName, { type: "image/jpeg" });
              callback(imgFile);
            });
        }
        chooseStaticImg("http://biaoblog.cn:3000/uploads/1615366772320.png");
    

    如果请求文件用的axios可以这样:效果相同

         axios.get(url).then((res) => {
            let imgFile = new File([res.data], imageName, { type: "image/jpeg" });
            callback(imgFile);
          });
    

    第二步:

    把已经转成功的文件 上传到我们的服务器就完事了

        // 上传到我们自己的服务器
        function uploadFile(file) {
          var formData = new FormData();
          formData.append("file", file);
          console.log(formData.get("file"));
          fetch("http://localhost:3000/blogData/upload", {
            method: "POST",
            body: formData,
          // headers: {
            // //不需要写'Content-Type': 'multipart/form-data',自动是form -data 写了报错!离谱!
            // 'Content-Type': 'multipart/form-data',
            // },
          })
            .then((res) => {
              return res.json();
            })
            .then((res) => {
              console.log(res);
            });
        }
    


    后端使用node.js

    经过操作,发现上面说的第一种方法 依赖于new File 也就是前端的方法

    但是在node环境中 没有这样直接生成file的方法怎么办呢?

    答案是通过fs.readfile

    首先放弃一种用户传递file这种方式 单独写个接口来处理

    下面是方法.

    主要是通过axios去请求这个图片的url,可以指定返回的数据格式为:arraybuffer

    然后writeFile是直接buffer的 ,直接指定路径写入就可以了,实现了我们的需求,不需要依赖于前端的file对象了

    封装了一层promise来处理异步,compressImg方法是我们压缩图片的方法 如果需要可以参考:http://biaoblog.cn/info?id=1661684128265

    不需要可以忽略,

    当时还是很纠结node该如何转成前端那种file再去调用我们之前的upload方法,后来想通了

    不一样非要用一样的方法,只要能达到我们的效果即可!

    我们遇到的问题 别人的描述:https://cnodejs.org/topic/60c31420248d04610b4acab0

    const saveCrawlerImg = async (dataSrc) => {
      console.log(dataSrc);
      let files = {
        detailSrc: "",
        coverSrc: "",
      };
    
      return new Promise((resolve) => {
        axios
          .get(dataSrc, {
            responseType: "arraybuffer",
          })
          .then(async (res) => {
            let filename = Date.now() + ".jpg";
            fs.writeFile("./public/uploads/" + filename, res.data, async (err) => {
              if (err) {
                console.log(err);
              } else {
                files.detailSrc = IPAddress + "/uploads/" + filename;
                let coverName = filename.split(".")[0] + "_cover";
                await compressImg(
                  `./public/uploads/${filename}`,
                  coverName,
                  "public/uploads/compress"
                );
                files.coverSrc =
                  IPAddress + "/uploads/compress/" + coverName + ".jpg";
                resolve(files);
              }
            });
          });
      });
    };
    


    2024/3/21更新

    前端根据后端返回的字节流,转为图片并下载

      const downFileAction = (record) => {
        downLoadContractPreview(record.id)
          .then((data) => {
            console.log('data__', data)
            let blob = data.response
            downImgFromBlod(blob)
          })
          .catch((err) => showFetchErrorMsg(err))
      }
    
    export const downImgFromBlod = (blob) => {
      // 创建一个 <a> 标签
      var link = document.createElement('a')
      link.href = URL.createObjectURL(blob)
      link.download = 'image.jpg' // 指定文件名,可以根据需要更改
      link.click() // 模拟点击 <a> 标签进行下载
      // 释放 URL 对象
      URL.revokeObjectURL(link.href)
    }