Unable to use res.send and res.download in Node/Express due to headers already being set - node.js

I am new to Node, and I am trying to make it so that when I go to 'localhost:1337/download/open' it renders a webpage, as well as download a file.. I understand that you can only set a header once (that is the error I am getting), but what is the easiest way to both render html AND download a file? Code below:
const express = require('express');
const app = express();
app.get('/download/open', function (req, res) {
let file = `${__dirname}/downloads/Open Tasks.csv`;
res.download(file);
res.send("words");
})
app.listen(1337, function (err) {
if (err) {
console.log(err)
return
}
console.log(`App running. listening on: http://localhost:1337`);
});
Error:
Error: Can't set headers after they are sent.
Thank you in advance.

I was able to figure out what I was trying to do. Instead of trying to render a whole new page AND download a file, I needed to dedicate a route to just a download through the use of an <a></a> tag.
For instance, if I have a webpage at 'http://localhost:1337' that has a link on it like:
Download Open Tasks
Download Open Tasks
Then in node.js I have a route for 'download/open' like so:
app.get('/download/open', function (req, res) {
let file = `${__dirname}/downloads/Open Tasks.csv`;
res.download(file);
})
It will not open a new page (like I thought it needed to) it will just download the file.

IMO, I would suggest you should do the following to achieve your goal:
render the HTML result for "GET http://localhost:1337/download/open"
In the HTML file /download/open, put AJAX block to invoke download file operation
(Download a file by jQuery.Ajax)
$(document).ready(function(){
//code to invoke download file....
});

Related

How to process JS file returned from Express response.sendFile()

I have an API which uses Node.js + Express on the backend.
For one of the API endpoints, I'd like to use the Express response object method of "sendFile", documented here:
https://expressjs.com/en/api.html#res.sendFile
The API should return a Javascript file through the sendFile method.
What I can't figure out is how to read in the .js file on the front end so that I can use the JavaScript functions defined in the file. The sendFile portion appears to be working -- it's just the use of the file which I can't figure out.
Here's what I'm doing on the backend:
app.get("/api/member", async (req, res) => {
options = {
root: path.join(__dirname, '/static'),
dotfiles: 'deny'
}
res.sendFile("member.js", options, (err) => {
if (err) {
console.log(err)
next(err)
} else {
console.log('Sent file')
}
})
});
This seems to be working fine, as I can navigate to the endpoint on my localhost and it loads the JS file. The file member.js simply contains some javascript function definitions.
But, I can't figure out how to consume/use the file once it arrives to the front end.
Here's what I have currently on the frontend:
async function refreshJS() {
const url = `${baseUrl}/member`;
const response = await fetch(url, { credentials: "include" });
const script = document.createElement("script")
script.type = "text/javascript"
script.src = response.body
document.head.appendChild(script)
eval(script)
}
I've spent a lot of time looking through the console/debugger to find the text associated with the JS functions -- but they're nowhere to be found.
I've tested this general framework by loading JS files locally through the console and it worked, so I think it's wrapped up in a misunderstanding of where the JS functions live in the API response. For example, if I replace the command above of:
script.src = response.body
with
script.src = "member.js"
then everything works fine provided I have the file locally.
The examples that I've reviewed seem to deal exclusively with sending an HTML file which is loaded on the frontend. But, I can't find supporting documentation from the fetch API to understand how to use the JS file contents.

Onclick function pug from node

I passed function to render in my pug file. What I want is when the button is clicked, the function should start, but the function starts when I enter the site. Below is how I passed function and using this in PUG file
Router
const start = require('../bot')
exports.home = (req, res) => {
res.render('home', {
functionOne: start.mainFunction()
});
}
PUG File
html
head
link(rel="stylesheet" href="https://fonts.googleapis.com/css?family=Montserrat:300,400,500,700")
link(rel="stylesheet" href="/css/main.css")
body
button(type="button" id="mybutton" onclick="functionOne")
The res.render statement is only meant to send data to the template, you can't send a function through there. The Express documentation explains this.
The function is running when you request the page because that's actually what you're telling it to do when you include that function in there.
You will need to write some client-side JavaScript to make an AJAX call or form POST then create a new ExpressJS route on the server to capture that and run the function.

Serve a file in a browser from a runtime directory using nodejs

In our application we store our reports in a user defined folders. User can add their own folders during runtime. Iam showing the history of those files in a web page. on clicking the file name i should show the file from the folder. How can i show the files from a non public directory.Since its given during runtime i havent added them as static dir to the express server.
One idea we tried was to use node-static-server and create a file server with the folder and serve the file. for each file we create this. it works fine but i get an error saying "port already in use". is there any better idea to do this? is this the right approach?
You can do this in NodeJS using a express.static:
const FS = require('fs')
const express = require('express')
const bp = require('body-parser')
const app = express()
function fileTest(req, res, next){
if (/\.|\/|\\/.test(req.params.file))
return res.sendStatus(400)
return next();
}
app.get(
'/static/:file',
fileTest,
function(req, res, next){
req.url = req.url.replace('/static','')
next()
},
express.static(
'./static',
{
fallthrough: false
}
)
)
app.post(
'/static/:file',
fileTest,
bp.text(),
function (req, res) {
FS.writeFile(
'./static/'+req.params.file,
req.body,
function (err) {
if(err)
return res.sendStatus(500)
return res.sendStatus(200)
}
)
}
)
app.listen(
1337
)
This is a simple example showing a server that will:
[POST]
Take a text body and load it into memory( pitfall: large bodies in memory )
Based on the URL, save it as a file in the static folder
[GET]
Search for a file
If found return file
The good news is that you can make the file and then request the file without restarting the server. Bad news is that this is a VERY SLOW server( comparatively to other options ).
As with all examples no good practices were followed, so be sure to adapt it to your needs.
Things to think about as you adopt it:
How do I allow people to save files to other folders?
How do I disallow people from saving files to other folders I don't want them to?
PROPER AUTHORIZATION

Send PDF as response to client

I'm facing a strange behaviour with PdfKit. I'm using Nodejs and Express. When I call my route that generate the PDF, the route itself is called twice, and I don't understand why.
Below is the smallest code that recreate this:
var express = require('express'),
app = express();
app.get('/', function (req, res) {
console.log('Route called with referer', req.headers.referer);
var PdfDocument = require('pdfkit'),
doc = new PdfDocument();
doc.pipe(res);
doc.addPage();
doc.end();
});
app.listen(7373, function () {
console.log('started');
});
In the terminal, I have these logs, refreshing only one time the page from the browser:
node tmp/server.js
started
Route called with referer undefined
Route called with referer http://127.0.0.1:7373/
Anyone knows why the route is called one more time automatically?
Ok, after some analysis, I found that it's the browser's PDF viewer that launch a second call. When using wget or curl, I see only one call and one log. So just be aware that code is parsed twice when diplaying the page from the browser.

Using directory (for images links etc) in Openshift (nodejs application)

I have a webpage that I have hosted using a node application on openshift. Its here
http://nodejs-volition.rhcloud.com/
My question is very simple (although I haven't found anyone else asking it). How do I refer to other files in the directory which contains index.html
For instance I would like to use an image that is in the directory in the index. My current html for the image is
<img src="$OPENSHIFT_REPO_DIR/images/1416870991752.jpg" alt="spark core">
I have also tried using "images/1416870991752.jpg". I have the same problem with linking to other html files in the directory?
What am I doing wrong? Please help?
As corey112358 alludes to below the key is in that to host using nodejs a server must be defined. My application already has a server file, so rather than creating a new server I must modify the existing one. I've done it successfully now, there were two changes to make to the server.js file.
The 1st change is modification of the cache. That should look like this...
self.zcache['index.html'] = fs.readFileSync('./index.html');
self.zcache['page2.html'] = fs.readFileSync('./page2.html');
self.zcache['sparkcoredark.jpg'] = fs.readFileSync('./sparkcoredark.jpg');
The first line was already included but the next two were added by me to include another html page and an image.
The second step is modify the self.createRoutes section of the server.js file as below (asciimo image is included by default).
self.createRoutes = function() {
self.routes = { };
self.routes['/asciimo'] = function(req, res) {
var link = "http://i.imgur.com/kmbjB.png";
res.send("<html><body><img src='" + link + "'></body></html>");
};
self.routes['/'] = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.send(self.cache_get('index.html') );
};
self.routes['/page2.html'] = function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.send(self.cache_get('page2.html') );
};
self.routes['/sparkcoredark.jpg'] = function(req, res) {
res.setHeader('Content-Type', 'image/jpg');
res.send(self.cache_get('sparkcoredark.jpg') );
};
};
Hope that helps out anyone else struggling with this issue. Thanks to coreyfibonacci

Resources