How can I resolve this pdf-generator problem? - javascript

I'm new at field.
I trying to make pdf generator web application with express.js using html-pdf package.
I have condition on engagement variable
module.exports =
({rs,periode,engagement,siren,num,rue,codePostal,ville,contratRef,commentaire,nomPrenom,fonction,phone,mail}) => {
const today = new Date();
return `
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<script>
window.onload = function test() {
var o = (document.getElementById('choix1'));
var u = (document.getElementById('choix2'));
if (${ engagement } == "oui") {
o.checked = true;
}else if (${ engagement } == "non") {
u.checked = true
}
}
</script>
When client send data to back end the app crashed and error "cannot set headers after they are sent to the client" in my terminal. how can I resolve this problem ?
Server API code:
app.post('/pdf', (req, res) => {
pdf.create(pdfDocument(req.body), {}).toFile('result.pdf', (err) => {
if(err) { res.send(Promise.reject()); }
res.send(Promise.resolve());
});
});

We normally get cannot set headers after they are sent to the client if response is returned twice or if headers are set after response is returned. You can read more about it in following stack overflow post:
Error: Can't set headers after they are sent to the client
If response object is not being updated from any other middleware apart from request handler code shared, there are chances that pdf.create returned error and res.send got called twice -
within if block for error and
res.send statement after if
If you add return before res.send like below, issue should be resolved
app.post('/pdf', (req, res) => {
pdf.create(pdfDocument(req.body), {}).toFile('result.pdf', (err) => {
if(err) {
return res.send(`Error in generating PDF`);
}
return res.send(`PDF created successfully!`);
});
});
Also, I am not sure why you are returning Promise.resolve() / Promise.reject() in response.

Related

How to get a variable from front to a service worker?

Some context
I've created a service worker to send notifications to registered users.
It works well until I tried to implement a sort of id to each people who register to a service worker (to send notification).
I do that because I have to delete old registration from my database, so I took the choice to let each users three registration (one for mobile device and two others for different navigator on computer) and if there is more, I want to remove from the database the older.
Tools
I'm using nodejs, express and mySql for the database.
The issue
When I launch a subscription I got this error:
SyntaxError: Unexpected token o in JSON at position 1
at JSON.parse (<anonymous>)
I saw in an other post that it's because they try to JSON.parse what's already an object.
But in my case, I can't find where I parse, see the part which are concerned:
// service.js (service worker file)
// saveSubscription saves the subscription to the backend
const saveSubscription = async (subscription, usrCode) => {
const SERVER_URL = 'https://mywebsite:4000/save-subscription'
subscription = JSON.stringify(subscription);
console.log(subscription); // I got here what I expect
console.log(usrCode); // <-------------------------------- HERE I GOT UNDEFIND
const response = await fetch(SERVER_URL, {
method: 'post',
headers: {
'Content-Type' : 'application/json',
},
body : {
subscription: subscription,
usrCode: usrCode
}
})
return response
}
But when I console.log(usrCode) in my inspector, I got the good value.
So how should I do to get the value in service.js
Maybe the problem is from:
const bodyParser = require('body-parser')
app.use(bodyParser.json())
At the beginning I thought that the issue is from the back (because I'm not really good with async function).
And here is the back, If maybe I got something wrong.
// index.js (backend)
// Insert into database
const saveToDatabase = async (subscription, usrCode) => {
// make to connection to the database.
pool.getConnection(function (err, connection) {
if (err) throw err; // not connected!
console.log(usrCode);
console.log(subscription);
connection.query(`INSERT INTO webpushsub (webpushsub_info, webpushsub_code) VALUES ('${subscription}', '${usrCode}')`, function (err, result, fields) {
// if any error while executing above query, throw error
if (err) throw err;
// if there is no error, you have the result
console.log(result);
connection.release();
});
});
}
// The new /save-subscription endpoint
app.post('/save-subscription', async (req, res) => {
const usrCode = req.body.usrCode; // <------------------ I'm not sure about this part
const subscription = req.body.subscription
await saveToDatabase(JSON.stringify(subscription, usrCode)) //Method to save the subscription to Database
res.json({ message: 'success' })
})
By searching on google, I've found this tutorial. So the reason why usrCode is undefined is because the service worker doesn't have access to a data stored in front.
First you have to pass it in the URL as following:
// swinstaller.js (front)
// SERVICE WORKER INITIALIZATION
const registerServiceWorker = async (usrCode) => {
const swRegistration = await navigator.serviceWorker.register('service.js?config=' + usrCode); //notice the file name
return swRegistration;
}
And then get it in the service worker:
// service.js (service worker file)
// get the usrCode
const usrCode = new URL(location).searchParams.get('config');

I'm unable to send a response to my react.js using http.get in node

I'm trying to get the temperature data from my node.js backend sent to react.js but i kept getting res.send is not a funtion
Sample code here
app.get("/gettemperature", (req, res) => {
const email = req.query.email;
let stmt = `SELECT * FROM users WHERE email=?`;
let todo = [email];
db.query(stmt, todo, (err, results, fields) => {
if (err) {
console.error(err.message);
}
if(results.length > 0 ){
let id = results[0].id;
let getID = `SELECT * FROM controlModules WHERE deviceowner=?`;
let getidData = [id];
db.query(getID, getidData, (err, resulta, fields) => {
if (err) {
console.error(err.message);
}
if(resulta.length > 0){
let lanip = resulta[0].ipaddress;
let url = "http://"+lanip+"/data";
http.get(url,(res) => {
let body = "";
res.on("data", (chunk) => {
body += chunk;
});
res.on("end", () => {
try {
let json = JSON.parse(body);
const temp_actual = json.temperature.value;
console.log(temp_actual);
res.setHeader('Content-Type', 'application/json');
res.end(
JSON.stringify({
value: temp_actual
})
);
} catch (error) {
console.error(error.message);
};
});
}).on("error", (error) => {
console.error(error.message);
});
}
});
}
});
});
i really need to return/send/respond the temperature data to my front end but i'm getting said error, is there a different way to return data?
It looks like you are mixing up an HTTP server you wrote in Node (although you haven't shown any relevant code) and an HTTP client you also wrote in Node.
res is an argument received by the callback you pass to http.get and contains data about the response received by your HTTP client.
Meanwhile, somewhere else (not shown) you have a different variable also called res which is the object your HTTP server uses to send its response to the browser running your React code.
You are calling res.send and wanting res to be the latter but it is really the former.
Since you haven't shown us the HTTP server code, it is hard to say where that res is, but there is a good chance you have shadowed it and can solve your problem by using different names (e.g. client_res and server_res).
That said. I strongly recommend avoiding using the http module directly as the API follows out of date design patterns and isn't very friendly. Consider using fetch or axios for making HTTP requests and Express.js for writing HTTP servers.

why am I getting 'GET/ 304 --' in my code? (vue.js, express)

When I request data on client(vue.js) with axios,
I got a error code in server side, 'GET/ 304 --'
But I don't know why this happened
and how to approach this problem or how to fix that.
If I delete codes about 'axios' on client side,
That error doesn't show up.
Please can someone help me.
the code below:
Client side
created() {
axios
.get("http://localhost:4000/")
.then(
result => (
(this.greeting = result.data.greeting),
(this.greeting2 = result.data.greeting2)
)
);
}
Server side
export const getHome = async (req, res) => {
let user;
if (req.headers.authorization !== undefined) {
try {
user = auth.verify(req.headers.authorization);
user = await models.User.findOne({
where: { id: user.id }
});
} catch (err) {
console.log(err);
}
} else {
user = null;
}
const name = user ? user.name : 'Please LOGIN';
res.json({ greeting: `Welcome to Chat N Chill`, greeting2: name });
};
auth.verify code on server side
verify(token) {
return jwt.verify(token.replace(/^Bearer\s/, ''), SECRET_KEY);
}
Express will automatically set the status code to 304 for requests that are fresh:
https://github.com/expressjs/express/blob/e1b45ebd050b6f06aa38cda5aaf0c21708b0c71e/lib/response.js#L206
The property fresh is defined here:
https://github.com/expressjs/express/blob/e1b45ebd050b6f06aa38cda5aaf0c21708b0c71e/lib/request.js#L467
It is documented here:
https://expressjs.com/en/4x/api.html#req.fresh
It should be nothing to worry about, it just means that the content of the response hasn't changed relative to what the browser already has in its cache.

Fill an array based on a get response express

I have the following server.js get route
app.get('/', function(req, res) {
var url;
var final_res = [];
endpoints.forEach(function(url){
request(url, function(error,response,body){
if(!error && response.statusCode == 200){
final_res.push(url.url);
console.log(url.url);
}else{
res.send(err);
console.log(err);
}
});
});
});
And this is my client js where I fetch this exact same get with jQuery
$(document).ready(function() {
$.get('http://localhost:3000/', function(data) {
console.log(data);
$("#body").text(data);
});
});
When I open my index.html it displays the user interface correctly and inside my terminal where I have executing my server.js it correctly displays the url. What I can't accomplish is how to use my data that my jQuery receives in order to populate a table inside my html. My table will be populated with urls that are fetch from my endpoints.
I have some background in nodejs but I cant wrap this up.
Since you need to know when multiple requests are done, I'd suggest you switch to using the request-promise library so you can use promises to track when all the requests are done. That library also checks the statusCode for you automatically. So, you can do this:
const rp = require('request-promise');
app.get('/', function(req, res) {
Promise.all(endpoints.map(url => {
return rp(url).then(r => {
return url.url;
}).catch(err => {
// rather than error, just return null result
return null;
})
})).then(results => {
// filter out null values, then send array as the response
res.json(results.filter(item => item !== null));
}).catch(err => {
console.log(err);
res.sendStatus(500);
});
});
This will run all the requests in parallel, but collect the results in order which should result in the fastest overall run time.
If you wanted to run them one a time, you could use async/await like this:
const rp = require('request-promise');
app.get('/', async function(req, res) {
let results = [];
for (let url of endpoints) {
try {
let r = await rp(url);
if (r) {
results.push(url.url);
}
} catch(e) {
// ignore error
}
}
res.json(results);
});
EDIT Jan, 2020 - request() module in maintenance mode
FYI, the request module and its derivatives like request-promise are now in maintenance mode and will not be actively developed to add new features. You can read more about the reasoning here. There is a list of alternatives in this table with some discussion of each one. I have been using got() myself and it's built from the beginning to use promises and is simple to use.
You must wait for all requests gets resolved to then send final_res array back to client. You can do this using async/await and Promise.all concepts. If you don't want to use these resources then you'll need to count and wait all request manually, using a counter to know when all requests has done, as below:
app.get('/', function(req, res) {
var url;
var final_res = [];
var respCounter = endpoints.length;
endpoints.forEach(function(url){
request(url, function(error,response,body){
respCounter--;
if(!error && response.statusCode == 200){
final_res.push(url.url);
console.log(url.url);
}else{
res.send(err);
console.log(err);
}
if(respCounter == 0) {
res.send(final_res);
}
});
});
});

UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 22): ReferenceError: client is not defined

This error seems to be coming up on every http request I make. I'm not totally sure where it's coming from?
(node:39390) UnhandledPromiseRejectionWarning: Unhandled promise rejection (rejection id: 22): ReferenceError: client is not defined
There is no line number in the error, but here is a sample of code that seems to be causing it:
try {
var client = await pool.connect();
await client.query(queryStatement, queryArgumentsArray);
res.sendStatus(200);
} catch (e) {
console.log('Error adding updating subvendor availability data, UPDATE SQL query task', err);
res.sendStatus(500);
} finally {
client && client.release && client.release();
}
It first I thought it must be coming from my finally block (maybe client was out of scope), but I added and if statement to explicitly prevent attempting to call client.release if it doesn't exist:
if (client) { client && client.release && client.release() };
I am still getting this error, so I feel like it must be coming from these lines.
var client = await pool.connect();
await client.query(queryStatement, queryArgumentsArray);
res.sendStatus(200);
Am I misunderstanding how to use async? To be clear, the code is functioning well and the http requests are working (responding correctly to the requests), my terminal is just getting flooded with these warnings.
Here is a simplified version of the full route:
var express = require('express');
var router = express.Router();
var pool = require('../modules/pg-pool'); // brings in pg-pool created in another module
// This route updates the availability for a user
router.put('/updateAvailability', async (req, res) => {
var userId = req.decodedToken.userSQLId;
var subvendorId = req.headers.subvendor_id;
var availability = req.body;
var queryStatement = 'UPDATE status SET status=$3 WHERE userId=$2';
var queryArgumentsArray = [availability.status, userId ];
try {
var client = await pool.connect();
await client.query(queryStatement, queryArgumentsArray);
res.sendStatus(200);
} catch (e) {
console.log('Error updating subvendor availability data, UPDATE SQL query task', err);
res.sendStatus(500);
} finally {
client && client.release && client.release();
}
});
module.exports = router;
All credit here goes to brianc the creator of node-postgres who answered my question here after I received the suggestion that it might be a problem with that library (doesn't seem like it was). I simply needed create the client outside of the try-catch
var client = await pool.connect()
try {
await client.query(...)
res.sendStatus(200)
} catch { ...}
finally {
}
His full answer can be found here: https://github.com/brianc/node-postgres/issues/1301

Categories

Resources