Image upload to server in node.js without using express
javascript, node.js
Solution
What has to be taken into consideration is the fact that the received data from the upload has this sort of format:
------WebKitFormBoundary9BhXe3lt2UddCDz9
Content-Disposition: form-data; name="document"; filename="globeSS.jpg"
Content-Type: image/jpeg
ÿØÿà JFIF d d ÿì Ducky d ÿá
//[binary binary binary...]
Ï[leñnœ“}ÛOyŠVÑ0êãXÂ}Ö'±”É iÉöÚ$GTQ7äŽø
uÚ_êÍòXgV¿Õ=€q`]aKRÐÀ
ò<ÿÙ
------WebKitFormBoundary9BhXe3lt2UddCDz9--
To get the binary data only( and thus the file), the programmer has to figure out a way to clip the binary out of that data. In the below code, binary of the picture is all saved in memory, so if the user uploads a particularly large file, the following implementation might fail. It'd be best to try to write down the file in chucks.
request.setEncoding('binary');
//Grabbing all data from the image
var body = ''
var binaryEnd; //gets the string that indicates the location of the end of the binary file
var first = true;
request.on('data', function(data) {
if(first)
binaryEnd = data.toString().substring(0, data.toString().indexOf('\n')-1);
first = false;
body += data
});
//Dealing with the image once we have everything
request.on('end', function() {
var note = querystring.parse(body, '\r\n', ':')
console.log(note)
//making sure than an image was submitted
if (note['Content-Type'].indexOf("image") != -1)
{
//get the filename
var fileInfo = note['Content-Disposition'].split('; ');
for (value in fileInfo){
if (fileInfo[value].indexOf("filename=") != -1){
fileName = fileInfo[value].substring(10, fileInfo[value].length-1);
if (fileName.indexOf('\\') != -1)
fileName = fileName.substring(fileName.lastIndexOf('\\')+1);
console.log("My filename: " + fileName);
}
}
//Get the type of the image (eg. image/gif or image/png)
var entireData = body.toString();
var contentTypeRegex = /Content-Type: image\/.*/;
contentType = note['Content-Type'].substring(1);
//Get the location of the start of the binary file,
//which happens to be where contentType ends
var upperBoundary = entireData.indexOf(contentType) + contentType.length;
var shorterData = entireData.substring(upperBoundary);
//replace trailing and starting spaces
var binaryDataAlmost = shorterData.replace(/^\s\s*/, '').replace(/\s\s*$/, '');
//Cut the extra things at the end of the data (Webkit stuff)
var binaryData = binaryDataAlmost.substring(0, binaryDataAlmost.indexOf(firstLine));
//Write to a file
fs.writeFile('./images/' + fileName , binaryData, 'binary', function(err)
{
//forward to another location after writing data
response.writeHead(302, {
'location':'/index.html'
});
response.end();
});
}
else
respond(404, "Please input an image", response);
});
This should work in all browsers (please note that internet explorer does not limit its data with `------WebkitFormBoundary`, but something else (I think only `-----`, but I forgot.)
Problem
Below is my server code where I try to get the file that was uploaded. However, `fs.writeFile`doesn't work, so I'm assuming that I'm doing something wrong. ``` server.on('request', function(request, response){ .... if((pathArray[1] == "photos") && (pathArray[2] = "new")){ var imagesPath = './images'; uploadPhoto(response, imagesPath); } else if(path == '/document/save'){ console.log("path: " + path); var body = ''; request.on('data', function(data){ body += data; }); request.on('end', function() { var note = querystring.parse(body); console.log("Body data: " + note); var newPath = "./images/myimage.jpg"; fs.writeFile( newPath, body, function (err) { if (err) throw err; }); }); } ``` Here is my HTML for the form, if it helps anyone: ``` function uploadPhoto(response, imageLoc){ response.writeHead(200, { 'Content-Type': 'text/html' }); response.write('<html><body>'); response.write('<div class="uploadFile">'); response.write('<link rel="stylesheet" type="text/css" href="style.css">'); response.write('<form action =/document/save>'); response.write('<method = "post">'); response.write('<enctype="multipart/form-data">'); response.write('<label for="name">Upload new photo</label>'); response.write('<br></br>'); response.write('<input type="file" name="name">'); response.write('<br></br>'); response.write('<button type="submit">Upload</button>'); response.write('</div>'); response.write('</body></html>'); response.write('</form>'); response.end(); } ``` After I upload the file, url goes to /document/save/uploadImage.jpg. But when I try to read the content of the image ("body") to save the image into a folder and then display it, seems that the content of the object of the request is empty. How do I get the content of the image using `node.js` without express, or any other external libraries than what I have? Is `fs.writeFile` a good function to use when writing a binary file?