Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Nodejs: How return different content types with same response (text and image)?

I'm trying to learn nodejs and I thought the best way to do this would be to try doing some stuff without using express or any other non-core modules. I'm stuck on trying to get some text and an image to be delivered simultaneously. The code I'm trying is:

var http = require('http');
var fs = require('fs');

var server = http.createServer(function(request,response) {

    fs.readFile('my_pic.jpg', function(error, file) {
        response.writeHead(200, {'content-type':'text/html'});
        response.write('<p>hi there!</p>');

        response.writeHead(200, {'content-type':'image/jpg'});
        response.write(file, 'image');

        response.end();
    });

});

var port = process.env.PORT || 8080;

server.listen(port, function() {
    console.log('Listening on port ' + port);
});

So ideally what should be delivered is:

<html>
<body>
<p>hi there</p>
<img src='my_pic.jpg'/>
</body>
</html>

But instead, nothing is appearing.

I tried putting a response.end() after writing 'hi there', which displays the text, and after that I tried swapping the places of the text and picture (headers included), which displayed the picture, but I can't figure out how to get both to display simultaneously, like on a real web page.

Can you explain how to go about putting in different types of content onto the same webpage - do they need to be in different responses? Something I came across on another question:

nodejs - How to read and output jpg image?

Something like that looks like the solution, but I can't figure out how to apply this to my situation (I don't have a lot of experience in the server side of things.)

Many thanks

EDIT: got it working from user568109's reply:

var http = require('http');
var fs = require('fs');


var server = http.createServer(function(request,response) {
fs.readFile('my_pic.jpg', function(error, file) {

    var imagedata = new Buffer(file).toString('base64');

    response.writeHead(200, {'content-type':'text/html'});
    response.write("hi there!<img src='data:my_pic.jpg;base64,"+imagedata+"'/>");
    response.end();

    });

});

var port = process.env.PORT || 8080;

server.listen(port, function() {
    console.log('Listening on port' + port);
});

This seems like a lot of work in embedding images though - if I wanted to put more than one image in, I'd have to just keep nesting those filestream callbacks?

I also tried it this way but it doesn't work:

var http = require('http');
var fs = require('fs');

var server = http.createServer(function(request,response) {

    response.writeHead(200, {'content-type':'text/html'});
    response.write("hi there!<img src='my_pic.jpg'/>");
    response.end();

});

var port = process.env.PORT || 8080;

server.listen(port, function() {
    console.log('Listening on port' + port);
});

I wasn't sure if this was what people meant by the line

response.write('<img src="my_pic.jpg"/>')

, because the server doesn't seem to be making another request on my behalf to go fetch the image? It's just showing a broken icon image.

like image 647
xdl Avatar asked Feb 14 '13 23:02

xdl


2 Answers

If you do response.write('<img src="my_pic.jpg"/>'); as mentioned above the image file would be sent only when browser sends GET for the image. It would become multi-part request.

Or you can do it like this. It is possible to send your image in binary form in HTML. Use :

<img src="data:image/gif;base64,imagedata">

where imagedata is a base64 encoding of gif image. So do this in node.js :

//Write text in response.
content = get-image-file-contents;     //store image into content
imagedata = new Buffer(content).toString('base64');    //encode to base64
response.write('<img src="data:image/gif;base64,'+imagedata+'">');//send image
response.end();

Check here for correct image conversion NodeJS base64 image encoding/decoding not quite working

This sends one response which sends both text and image. Only one header is required for response response.writeHead(200, {'content-type':'text/html'});

like image 63
user568109 Avatar answered Nov 10 '22 12:11

user568109


You can only write one value to a given header, so the second header is overwriting the first. Two solutions are

  1. write out a url to the image in the html - will be slightly slower for the user (needing an extra http request to fetch the image), but depending on the use case this is normally acceptable and very simple to implement
  2. convert the image to a data-uri string and include this in the html as the source of the image. More complicated to implement than the first approach ( I don't know of any libraries for doing the conversion in node) and with negligible benefits.
like image 1
wheresrhys Avatar answered Nov 10 '22 13:11

wheresrhys