Загрузка изображения с внешнего URL, сохранение на сервере с использованием JavaScript и ExpressJs

У меня борьба. Допустим, я получаю ответ JSON, который выглядит так:

{
    "items": [{
        "title": "test",
        "url": "http://urlToSomeImage.png",
        "description": "desc"
    }, {
        "title": "test",
        "url": "http://urlToSomeImage.png",
        "description": "desc"
    }]
}

Теперь все эти URL-адреса, если вы посещаете их через браузер, будут отображать изображение. Я хочу загрузить изображение и сохранить его на своем сервере по некоторому статическому пути + на основе имени по некоторому динамическому пути. Эта часть с путем проста, но путь для фактической загрузки файла с внешнего URL-адреса и размещения его на моем сервере, для этого я понятия не имею, с чего начать.

Я использую ExpressJS и vanilla javasript (запускается в среде nodeJs). Что мне нужно для этого? с чего начать?


person Foggy    schedule 29.11.2019    source источник
comment
Это недопустимый JSON   -  person Goodbye StackExchange    schedule 29.11.2019
comment
Извините, я отредактировал. Даже с этим, было бы неплохо вместо того, что вы написали, дать какой-нибудь совет.   -  person Foggy    schedule 29.11.2019
comment
Даже с этим... Я начинаю с того, что ты мне даешь. Когда вопрос в корне неверный с самого начала, я не обязан давать вам раздаточный материал, и я считаю грубым с вашей стороны просить меня дать вам совет вдобавок к этому.   -  person Goodbye StackExchange    schedule 29.11.2019


Ответы (1)


Если вы хотите сохранить изображение на сервере, ваш сервер должен загрузить файл и сохранить его.

Вот простой пример того, как я бы это сделал:

const path = require('path')
const fs = require('fs')
const URL = require('url').URL
const http = require('http')
const https = require('https')

// Define a function to download images from a passed array of URL's.
const downloadImages = (arr, folderpath = '') => {
  // - Create a new array of `Promise`s from the passed array, using `Array.map`
  //   and pass that new array to `Promise.all` so they are all waited for
  //   in-parallel.
  // - Each `Promise` in this new array resolves when the data specified in
  //   the passed array `item.URL` is downloaded and saved to a file with the
  //   appropriate name.
  return Promise.all(arr.map(item => {
    // For each item in the passed array...

    // Create and return a Promise which:
    return new Promise((resolve, reject) => {
      // Creates a `WriteStream` to a local file on path:
      // '[root directory path]/[folderpath]/[item.title].[extension]'
      const extension = path.extname(item.url)
      const filepath = `${path.dirname(process.mainModule.filename)}${folderpath}/${item.title}${extension}`
      const writeStream = fs.createWriteStream(filepath)

      // Reject if there's an error acquiring or writing to the `WriteStream`.
      writeStream.on('error', reject)

      // - Ensure we use the appropriate http module for downloading the file.
      // - If the `item.url` is HTTPS we use the `https` module, otherwise we
      //   use the `http` module.
      const protocol = new URL(item.url).protocol
      const requester = protocol === 'https:' ? https : http

      // Get a stream to the data on the URL.
      requester
        .get(item.url, res => {
          // Reject the Promise if the HTTP status code is not 200.
          if (res.statusCode !== 200) {
            return reject(`${item.url} failed, HTTP status: ${res.statusCode}`)
          }

          // Otherwise pass the stream to the `WriteStream` so it can be written
          // to the local file.
          res.pipe(writeStream)
          // When it's done, resolve the Promise.
          writeStream.on('finish', resolve)
        })
        .on('error', reject) // Also reject if there's a generic request error.
    })
  }))
}

// Test the function in an async IIFE since we are going to use await.
;(async () => {
  try {
    // `downloadImages` returns a Promise so we need to await it.
    await downloadImages([
      {
        title: 'lenna-color',
        url: 'https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'
      },
      {
        title: 'lenna-grayscale',
        url: 'https://www.ece.rice.edu/~wakin/images/lenaTest3.jpg'
      }
    ])
    console.log('done')
  } catch (err) {
    console.error(err)
  }
})()

Вас интересует функция downloadImages(arr, folderpath), которую я определил выше.

Если вы хотите сохранить изображения в корневой каталог, вы вызываете его так:

await downloadImages([
  {
    title: 'lenna-color',
    url: 'https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'
  },
  {
    title: 'lenna-grayscale',
    url: 'https://www.ece.rice.edu/~wakin/images/lenaTest3.jpg'
  }
])

или сохранить в папке с именем «images», которая существует в корневом каталоге:

await downloadImages([
  {
    title: 'lenna-color',
    url: 'https://upload.wikimedia.org/wikipedia/en/7/7d/Lenna_%28test_image%29.png'
  },
  {
    title: 'lenna-grayscale',
    url: 'https://www.ece.rice.edu/~wakin/images/lenaTest3.jpg'
  }
], '/images')
person nicholaswmin    schedule 29.11.2019
comment
Это выглядит чрезвычайно полезным! Спасибо, я попробую это позже. Где мне точно указать, где мне сохранить файл на моем сервере? - person Foggy; 29.11.2019
comment
В 1_. Первый параметр принимает путь к файлу. - person nicholaswmin; 29.11.2019
comment
Ты обалденный! Большое спасибо. - person Foggy; 29.11.2019