【问题标题】:How to get an image from another origin to my backend?如何从另一个来源获取图像到我的后端?
【发布时间】:2021-03-23 12:21:42
【问题描述】:

我试图弄清楚如何从其他域的图像 URL 中获取图像,然后发布到我的服务器。但我遇到了核心问题。

我正在制作一个愿望清单页面,用户可以在其中输入来自任何网站的产品的网址。我的服务器抓取产品信息和产品图像的 URL 并将其发送给客户端。用户细化信息并选择所需的图像。此信息被发送到后端以创建包含产品信息和商品图片的愿望清单商品。

抓取产品图片和产品信息

图像和信息在愿望清单上

污染的画布

我尝试使用画布抓取和裁剪图像并将其发送到我的后端。但是,当您将未经 CORS 批准从其他来源加载的图像绘制到画布中时,画布就会被污染。

在受污染的画布上调用以下任何一个都将导致错误:

  • 在画布上下文中调用 getImageData()
  • 在元素本身上调用toBlob()
  • 在画布上调用toDataURL()

source

      export async function toDataURLCanvas(src, outputFormat) {
        return new Promise((resolve) => {
          const img = new Image();
          img.onload = async function () {
            console.log(this);
            const canvas = document.createElement('canvas');
            const ctx = canvas.getContext('2d');
            canvas.width = 200;
            canvas.height = 200;
            ctx.drawImage(this, 0, 0); //this is where you would crop the image
            const blob = await new Promise((resolve) => {
              // results in "Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported.""
              canvas.toBlob((blob) => {
                resolve(blob);
              }, 'image/jpg');
            });
            resolve(blob);
          };
          img.src = src;
        });
      }

这给出了一个错误:

Failed to execute 'toBlob' on 'HTMLCanvasElement': Tainted canvases may not be exported.

所以我不能使用画布将图像 URL 转换为格式以发送到我的后端,例如 blob。

XHR

我尝试使用XMLHttpRequest() 将 URL 转换为数据 URL

   async function toDataURLXHR(url) {
        return new Promise((resolve) => {
          var xhr = new XMLHttpRequest();
          xhr.onload = function () {
            var reader = new FileReader();
            reader.onloadend = function () {
              resolve(reader.result);
            };
            reader.readAsDataURL(xhr.response);
          };
          xhr.open('GET', url);
          xhr.responseType = 'blob';
          xhr.send();
        });
      }

但是 CORS 可能是个问题。我在浏览器控制台中得到了这个:

Access to XMLHttpRequest at 'https://cdn-images.farfetch-contents.com/15/40/82/30/15408230_28680969_600.jpg' from origin 'http://localhost:3000' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

不可能?

似乎无法从一个站点抓取图像并将其发送到我的服务器。但是我看到其他网站这样做了,所以一定有办法。

【问题讨论】:

    标签: javascript canvas file-upload


    【解决方案1】:

    在后端抓取

    如果您正在抓取的地方没有 Access-Control-Allow-Origin 标头,您可能会遇到问题。

    坏消息是,您需要在服务器端运行此类请求才能解决此问题。

    source

    这表明这是可能的,但仅限于后端。

    我发现这个solution 将图像下载到后端。我们可以从客户端获取用户想要的图片的 URL 并使用此解决方案下载图片

    const imgURL = 'https://cdn-images.farfetch-contents.com/15/40/82/30/15408230_28680969_600.jpg';
    const fs = require('fs');
    const https = require('https');
    
    /* ============================================================
      Promise-Based Download Function
    ============================================================ */
    
    const download = (url, destination) =>
      new Promise((resolve, reject) => {
        const file = fs.createWriteStream(destination);
    
        https
          .get(url, (response) => {
            response.pipe(file);
    
            file.on('finish', () => {
              file.close(resolve(true));
            });
          })
          .on('error', (error) => {
            fs.unlink(destination);
    
            reject(error.message);
          });
      });
    
    /* ============================================================
      Download Image
    ============================================================ */
    
    (async () => {
      download(imgURL, `${__dirname}/public/newimg.jpg`);
    })();
    
    

    裁剪

    如果您想添加裁剪,您可以让客户端POST 将图像 URL 与裁剪信息一起发送到服务器,并且可以使用此backend canvas library 在后端进行裁剪。

    const imgURL = 'https://cdn-images.farfetch-contents.com/15/40/82/30/15408230_28680969_600.jpg';
    const fs = require('fs');
    
    const { createCanvas, loadImage } = require('canvas');
    
    const canvas = createCanvas(400, 400);
    const ctx = canvas.getContext('2d');
    
    loadImage(imgURL).then((image) => {
      const srcSqrDim = image.height > image.width ? image.width : image.width;
    
      ctx.drawImage(
        image,
        -(srcSqrDim - image.width) / 2,
        -(srcSqrDim - image.height) / 2,
        srcSqrDim,
        srcSqrDim,
        0,
        0,
        400,
        400
      );
      console.log(canvas.toDataURL());
      fs.writeFile(
        `${__dirname}/public/new1.png`,
        canvas.toDataURL().replace(/^data:image\/png;base64,/, ''),
        'base64',
        console.log
      );
    });
    

    【讨论】:

      猜你喜欢
      • 2013-08-11
      • 2021-11-21
      • 2020-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-17
      • 2018-02-15
      • 1970-01-01
      相关资源
      最近更新 更多