Downloading images

Now that we have uploaded our file and checked whether it's stored on the server, we want to be able to download it anytime. Let's create a route to download it. It will be just like the HEAD route we created, but now using the GET verb. Here's an example of how we can implement the route:

app.get("/uploads/:image", (req, res) => {
let ext = path.extname(req.params.image);

if (!ext.match(/^.(png|jpg)$/)) {
return res.status(404).end()
}

let fd = fs.createReadStream(path.join(__dirname, "uploads",
req.params.image));

fd.on("error", (e) => {
if (e.code == "ENOENT") {
return res.status(404).end()
}

res.status(500).end();
});

res.setHeader("Content-Type", "image/" + ext.substr(1));

fd.pipe(res);
});

We first start by checking the image extension:

let ext = path.extname(req.params.image);

If the extension is not .png or .jpg, we immediately return an HTTP response code 404, which means Not Found:

if (!ext.match(/^.(png|jpg)$/)) {
return res.status(404).end();
}

If the extension is acceptable, we create a readable stream to the image file path:

let fd = fs.createReadStream(path.join(__dirname, "uploads", req.params.image));

We then attach an error handler that will catch errors when reading the local file. If the error code is ENOENT, it means the file does not exist, so we again return an HTTP response code 404. For any other error codes, we return an HTTP response code 500, which means Internal Server Error:

fd.on("error", (e) => {
if (e.code == "ENOENT") {
return res.status(404).end()
}

res.status(500).end();
});

Returning code 500 is up to you. Perhaps you prefer to always return a 404 and hide the error differences from the user. That's a design decision; it depends on how you want your users to see your microservice and what target users will use it.

Then, we use the previously stored extension to set the content type returned to the user, in order to identify the image type we're sending. The content type should be in the format image/extension (without a dot):

res.setHeader("Content-Type", "image/" + ext.substr(1));

Finally, we pipe the file content to the response. This is a helper method that will trigger reads from the file stream and write them to the response. When the whole file has been read, the response is ended automatically:

fd.pipe(res);

Let's try it out. Restart our service and open your web browser. If you point to the previously uploaded image, you should get a copy of it:

If you change the path to something that you haven't uploaded, you should get an HTTP ERROR 404:

This is not very appealing. We can change our error handler to check whether the request might accept HTML content and return a custom message:

fd.on("error", (e) => {
if (e.code == "ENOENT") {
res.status(404);

if (req.accepts('html')) {
res.setHeader("Content-Type", "text/html");

res.write("<strong>Error:</strong> image not found");
}

return res.end();
}

res.status(500).end();
});

You should now receive a nicer response:

If you're familiar with Express, you could instead use a render engine and define a custom error template, or look for error handler modules that generate beautiful error pages.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset