简体   繁体   中英

Node.js: Get image file extension from request headers before downloading image

I am making a Node.js application used to download images. When I download an image I specify the file name for the image before downloading. However, unlike the name I do not know what the file extension of my image will be until I read the response headers and get the content-type . However, by the time I can read the response headers and create the full path for where I want the image to download to the request has already started piping the image to a blank address. Previously I started piping the image from inside the response event but was causing an issue where images would be truncated without throwing any errors if the internet connection was interrupted ( See ). This is my current code:

const fs = require('fs-extra');
var progress = require('request-progress');

var url = 'url to image';
var pathAndName = './Downloads/I want to call my image this'; // Does not include a file extension, just what I want the name of my image to be.
var req = request(url);
downloadImage(req, pathAndName).then(function(results) {
    console.dir(results);
}).catch(function(error) {
    console.error(error);
});

function downloadImage(req, pathAndName) {
    return new Promise((resolve, reject) => {
        if (!fs.existsSync(path.dirname(pathAndName))) fs.ensureDirSync(pathAndName);

        var response = null;
        var bytes = 0;
        var filename = '';
        progress(req, { delay: 0 }).on('progress', function (state) {
            // Report the download progress.
            console.log(state.speed);
        }).on('end', function () {
            // Check for errors before completing the download, the image might have been truncated even if a error was not triggered.
            if (response.statusCode == 200) {
                resolve({ bytes: bytes, filename: filename });
            } else {
                fs.unlinkSync(filename);
                reject({ 'name': 'StatusCodeError', 'message': response.statusCode });
            }
        }).on('response', function (resp) {
            response = resp;
            filename = pathAndName + '.' + mime.getExtension(response.headers['content-type']); // Here is too late to set the filename!
            bytes = response.headers['content-length'];
        }).on('error', function (error) {
            reject(error);
        }).pipe(fs.createWriteStream(filename)); // This needs to get the content-type returned by the response before piping!!!
    });
}

How can I download an image, determining its file extension from the response I get from the website and still properly handle download errors?

You need to call two requests in a series. First only for header with 'HEAD' instead of 'GET' where you will get an extension (and file size). Second with full request and response for real download. Here is example with callback but you can use it with a promise too.

function callbackWithYourDownload(contentType){
   /*... your download code ...*/
}
var xhr = new XMLHttpRequest();
    xhr.open("HEAD", url, true);

xhr.onreadystatechange = function() {
    if (this.readyState == this.DONE) {
        var contentType = xhr.getResponseHeader("Content-Type");
        callbackWithYourDownload(contentType);
    }
};
xhr.send();

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM