I am taking in a png file from AFNetworking saving it to GridFS and then I would like to be able to retrive it at some point. Out of curiousity I logged the image before it entered GridFS and it looks like..
<89504e47 0d0a1a0a 0000000d 49484452 00000074 0000008c 08020000 0022391a ...>
I save this in a buffer and then store it into GridFS.
When I am retrieving it via a GET request I log it again before sending it out and it appears to be in the same format.
Then I attempt to do this
res.writeHead(200, {'Content-Type': 'image/png' });
gs.createReadStream(image).pipe(res); //using GridJS this it the syntax to read
When viewing this in a browser it just appears like an empty or broken image link. If I inspect the page source it appears to be just
If I never set the headers it just appears as hundreds of lines of
<89504e47 0d0a1a0a 0000000d 49484452 00000074 0000008c 08020000 0022391a ...>
I feel like I am not converting a buffer right or something.
var http = require('http'),
MongoDB = require("mongodb"),
MongoClient = require("mongodb").MongoClient,
GridStore = require("mongodb").GridStore;
http.createServer(function (req, res) {
console.log("Serving request for file: " + req.url);
MongoClient.connect("mongodb://localhost:27017/test", {}, function(err, db) {
gridStore = new GridStore(db, req.url, "r");
gridStore.open(function(err, gs) {
if (err) {
console.log("error in open: " + err);
return;
}
res.writeHead(200, {'Content-Type': 'image/png'});
var s = gs.stream(true);
s.pipe(res);
});
});
}).listen(8124, "127.0.0.1");
console.log('Server running at http://127.0.0.1:8124/');
I can successfully run server and serve the png files successfully to the browser using the code pasted above. However since, you are saying that raw contents of the source does appear on client side when you do a "see source". I would suggest trying the code I wrote and see if that has the same issues.
Related
Here are the steps my application is doing:
User uploads an image (.PNG) file in the browser.
Browser sends the raw image data to my server.
The server then saves the file in my file system.
The problem is that my file system complains that the file is not a PNG file when I try to open it.
I'm trying to localize where the problem occurs without success. When I look at the file data using VIM it looks the same to me, with the same number of lines and the file contents both start with:
<89>PNG^M
^Z
^#^#^#^MIHDR^#^#^BD^#^#^#Î^H^B^#^#^#P6<8a><9a>^#^#^#^CsBIT^H^H^HÛáOà^ ^#^#_zTXtRaw profile type APP1^#^#^H<99>ãJOÍK-ÊLV((ÊOËÌIåR^#^Cc^S. ^SK^SK£D^C^C^C^K^C^H04006^D<92>F#
...
However, the file sizes are different, with the file I'm writing from my server being larger. So obviously they are different in some way.
I tried doing diff file1 file2 in the command line and it just gives me binary files differ without showing me the difference... ?? Strange.
So I'm currently confused about how the files differ, and where in my code this difference gets introduced...
I feel I'm missing some crucial knowledge about how some things work here under the hood, and I would very much appreciate if someone smarter than me could help me out here.
Code
Client:
<input id="icon-button-file" type="file" onChange={handleChange} />
<label htmlFor="icon-button-file">
<Button/>
</label>
function handleChange(event: any) {
if (!event.target.files[0]) return
const file = event.target.files[0]
const reader = new FileReader()
reader.onload = function (e) {
const instance = axios.create({
baseURL: 'http://localhost:3000/',
timeout: 5000,
headers: { 'Content-Type': 'application/json' }
})
instance.post(
'image',
JSON.stringify({
imageData: e.target.result.toString()
})
).then(result => {
console.log(result)
})
}
reader.readAsBinaryString(file)
}
Server:
app.post(`http://localhost:3000/image`, (req, res) => {
fs.writeFile('img.png', req.body.imageData, (err) => {
console.log(err)
})
})
EDIT:
I made it work by sending the image content to the server as a dataUrl instead, using reader.readAsDataUrl(). This encodes the image data as a Base64 string, which seems like a common practice. However, I'm still curious why sending the raw data doesn't work.
You can use Formidable to handle files in nodejs easily. Good to hear that you got it running already. I hope this helps to someone else. this covers some basics
and yes another approach is to encode to Base64 and decode back to a file from the server side. cheers
var express = require('express');
var router = express.Router();
var fs = require('fs');
var formidable = require('formidable');
/* GET home page. */
router.get('/', function(req, res, next) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write('<form action="fileupload" method="post" enctype="multipart/form-data">');
res.write('<input type="file" name="filetoupload"><br>');
res.write('<input type="submit">');
res.write('</form>');
res.end()
});
router.post(`/fileupload`, (req, res) => {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
var oldpath = files.filetoupload.path;
var newpath = './public/' + files.filetoupload.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.write('File uploaded and moved!');
res.end();
});
});
})
module.exports = router;
Answering my own question.
The reason for the problem was that I was sending the image binary data over http which can corrupt the data.
See: https://stackoverflow.com/a/201510/6017605
Since base64 encodes it as text, it can safely be transmitted.
This also helped me understand the problem: https://www.jscape.com/blog/ftp-binary-and-ascii-transfer-types-and-the-case-of-corrupt-files
So I'm very new to node.js and javascript, and i made a server that works great by loading up an html file on request. This html file does not contain any of it's own data, it simply sources from the internet and displays some images and text i wrote. I've decided to make the site play an audio file when it is opened. I know this is done easily with the <audio> tag in html5 but the src="" lets me take a file from the computer and place it there, of course when i open the site from another computer the file obviously isn't found and thus isn't played. I figure the audio file must be kept as a variable on the server and passed into the html file's <audio src= > tag. How do i do this? It is an .mp3(but i can get it to any other audio format) file about 30 seconds long. I just want it to play when the site is loaded from another computer(over the internet). Also how would i go about doing the same with pictures or any other data that i don't want to source from the internet but rather keep as data in my server?
var http = require('http');
var fs = require('fs');
var simpleServer = http.createServer(function(request, response){
response.writeHead(200, {"Content-Type":"text/html"});
fs.readFile('./Picture.html', null, function(error, data){
if(error){
response.writeHead(404);
} else{
response.write(data);
}
response.end();
})
});
simpleServer.listen(80, '0.0.0.0', function() {
console.log('Listening to port: ' + 80);
});
console.log("Server running...");
Short Answer
Bypassing using HTML altogether, you can also simply serve the audio file instead of Picture.html:
fs.readFile("./audiofile.mp3", function(error, data) {
if (error) {
response.writeHead(404);
} else {
response.writeHead(200, { "Content-Type": "audio/mpeg"});
response.end(data, 'utf-8');
}
});
Note:
You will have to replace the filename audiofile.mp3 and the content type audio/mpeg to their appropriate values for the file you want to send.
Check Mozilla's Complete List of MIME Types for a full list of file extensions and their associated content types.
Better Answer:
The http module is fairly low-level and is unnecessarily complicated if you're learning.
You can install express.js to your project using the command npm install express --save.
With express your code simplifies to:
const express = require('express');
const app = express();
const port = 80;
app.get('/', (request, response) => {
response.sendFile(__dirname + '/Picture.html');
});
// Anything put in the public folder is available to the world!
app.use(express.static(__dirname + '/public'));
app.listen(port, () => {
console.log(`Listening on port: ${port}`)
});
Then you just have to place all your files into a folder called "public" under your project directory and you can call them from HTML!
I have server.js and client.html.
Server.js is running on nodejs and is simply:
var http = require('http'), fs = require('fs');
var app = http.createServer(function(request, response) {
fs.readFile("client.html", 'utf-8', function(error, data) {
response.writeHead(200, {'Content-Type': 'text/html'});
response.write(data);
response.end();
});
}).listen(80);
and then I have client.html which is also very simply just
<img src="/public/images/avatar.gif">
Which just displays as though the image is not valid, I have checked the the director over and over and it is fine, why would it be doing this? I thought it might be because of the headers but text/html should surely display images?
Regards
Matt
It's not displaying the image because for every request (including the image request) it's returning the contents of clients.html.
If you want a static file server, i suggest looking at connect: http://www.senchalabs.org/connect/ or for something simpler, have a look at this: https://gist.github.com/rpflorence/701407
I am trying to learn the ins and outs of node. I know you can serve a file with a framework but I am trying to do it manually. I have a jpeg file in './public/logo.jpg'. When I send the request through localhost:8080 I don't get the image, just a blank screen with a generic image placeholder. What am I doing wrong? Thanks!
var http=require('http');
var url=require('url');
var fs=require('fs');
// creates a new httpServer instance
http.createServer(function (req, res) {
// this is the callback, or request handler for the httpServer
log('in server callback')
res.ins=res.write;
var parse=url.parse(req.url,true);
var path0=parse.pathname;
console.log(path0)
// respond to the browser, write some headers so the
// browser knows what type of content we are sending
var serveFile=function(){
var path='./public'+path0
fs.exists(path,function(e){
if(e){
log('serving file')
log(path)
fs.readFile(path,'binary',function(err,data){
if(data){
res.writeHead(200, {'Content-Type': 'image/jpeg'});
res.ins(data)
res.end()
}
})
}
else{
log('no file to serve')
log(path)
servePage()
}
})
}
serveFile()
}).listen(8080); // the server will listen on port 8080
Simply change the following two lines in your readFile callback :
res.writeHead(200, {'Content-Type': 'image/jpeg'});
res.write(data, 'binary');
Use response.write to send data to the client and set encoding to binary. (Default is utf-8)
I've recently ran into a very interesting problem while writing a web app with node.js.
Essentially, all I am doing is serving the index.html page to the client.
Here is the code:
var http = require('http');
var url = require('url');
var fs = require('fs');
var util = require('util');
var server = http.createServer(function(req, res){
var path = url.parse(req.url).pathname;
if(path == '/'){
console.log("LOADING INDEX...");
openIndex(req, res);
console.log("LOADING COMPLETE.")
} else {
res.write("Something went wrong...");
res.end();
}
}
);
var openIndex = function(req, res){
fs.readFile('./index.html', function(error, content){
if(error){
res.writeHead(500);
res.end();
}
else{
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(content, 'utf-8');
}
});
}
I've put some debugging statements just before and after the index.html page loads: "LOADING INDEX..." and "LOADING COMPLETE".
Now, I have shared the link to my server with my Facebook friends so they can see my app. Most of the time, everything works as it should, but once in a while I get this error:
LOADING INDEX...
This type of response MUST NOT have a body. Ignoring data passed to end().
and just now I've also gotten:
LOADING INDEX...
This type of response MUST NOT have a body. Ignoring write() calls.
The process never raches the "LOADING COMPLETE" statement.
I've tried to reproduce this countless times (accessing my app on different machines, browsers, devices, OS-versions) but every time it works as it should.
I've looked around for other people having this problem, and it seems that somehow, a body is getting into a GET response? I'm not entirely sure what this means or how to fix my code to prevent that from happening. Also, I'm not sure what the clients that produce this error see? Do they get to see my app? (i.e. are these just warnings and as far as they are concerned everything is fine?)
Any help with this will be greatly appreciated.
Xaan
If you're just using a static index.html, why not use express.static to serve it automatically?
app.use("/index.html", express.static(__dirname + '/index.html'));
This would cause expressjs to automatically handle HEAD requests, which should solve your problem.