I'm currently trying to generate a PDF with puppeteer, then render a page with a "thank you" message to the user. Once the user hits that page, the Puppeteer PDF will hopefully begin downloading on the user's machine. But I'm having some troubles.
I can successfully redirect the user to the page I want them on after collecting some basic info from a form:
app.post("/generatepdf", function (req, res) {
UserPdfRequest.create({ email: req.body.email, companyName: req.body.companyName }, function (err, createdRequest) {
if (err) {
console.log(err);
} else {
console.log(createdRequest);
res.redirect("/" + createdRequest._id + "/pdf-download");
}
})
});
Then, I send them to my route which handles finding the user in question, generating the PDF, then rendering the Thank You page:
app.get("/:companyId/pdf-download", function (req, res) {
UserPdfRequest.findById(req.params.companyId, function (err, foundRequest) {
if (err) {
console.log(err);
} else {
console.log(foundRequest);
(async () => {
const browser = await puppeteer.launch()
const page = await browser.newPage()
const url = 'http://localhost:3000/' + req.params.companyId + '/pdf-download';
await page.goto(url, {waitUntil: 'networkidle0'});
const buffer = await page.pdf({ format: "A4", printBackground: true });
res.type('application/pdf')
res.send(buffer)
browser.close()
})()
res.render("pdfDownload", { email: foundRequest.email, companyName: foundRequest.companyName });
}
})
});
But when I land on the Thank You page, my PDF does not begin downloading. Furthermore, my console.log(foundRequest) seems to log over and over again very rapidly in my terminal, and I also receive the following errors:
https://imgur.com/ZsApRHn
I know I'm probably in over my head here given I don't have much experience with async. I'm sure this is a simple fix I'm missing; however, any help (and explanation) would be extremely valuable and appreciated. Thank you for your time!
You are calling send and render on the same response object. You can either send the data or send html but you cannot do it for the same request.
Usually it is workarounded by opening a new tab for downloading.
Related
I followed several hundred links, most including stackoverflow links, to try to come up with a solution to this problem, but none yielded results.
I am simply trying to get the server to access client's detail via google. Ie, get the client's Google Sheets. I followed their documentation, but for the most part, its on client side only. I followed the instructions for server-side, but it has uncompleted work in it. I found out that the method to do is to have the client sign in via OAuth2.0 and then send the recieved code to the server to process to its very own access code. That is what I'm doing, however, when I try to query any data, I get that error in the title. Here is the code snippets, please let me know if there's anything I'm missing. RIP my rep.
server:
const Router=require("express").Router()
const auth=require("../utils/auth")
const fs= require("fs")
const {OAuth2Client}=require("google-auth-library")//I tried with this library instead, and it will give the exact same error.
const {google} = require('googleapis');
var auths=[]
function oAuth2ClientGetToken(oAuth2Client, code) {
return new Promise((resolve, reject) => {
oAuth2Client.getToken(code, (err, token) => { // errors out here
if (err) reject(err);
resolve(token);
});
});
}
async function formAuthClient(code) {
const {client_secret, client_id,redirect_uris} = JSON.parse(fs.readFileSync(__dirname+"/credentials.json"))
const oAuth2Client = new google.auth.OAuth2( // form authObject
client_id, client_secret,redirect_uris[1]
);
// var oauth2Client = new OAuth2Client(client_id,client_secret,redirect_uris[1]); other method
const token = await oAuth2ClientGetToken(oAuth2Client, code).catch(console.err);
// oauth2Client.credentials=token other method of oauth2.0
oAuth2Client.setCredentials(token);
return oAuth2Client;
}
Router.get("/",(req,res)=>{
res.render("home")
})
Router.post("/sheet",async (req,res)=>{
try {
const requestBody = {
properties: {
title:"hello"
}
};
var sheets= google.sheets({version:"v4", auth: auths[req.session.id]})
await sheets.spreadsheets.create(requestBody)
} catch (error) {
res.json(error)
}
})
Router.post("/login",(req,res)=>{
console.log("token: ",req.body.token);
req.session.token=req.body.token
console.log("req.session.id:",req.session.id);
auths[req.session.id]=formAuthClient(req.body.token)
res.status(200).json()
})
module.exports=Router
the client scripts is a simple button that will trigger an "getOfflineAccess" command and ask the user to log in and then send that data to the server with "/login". then, once another button is pushed, it will call "/sheet". I appreciate all help with this. I ran out of links to click on trying to solve this problem
I have a route like http://localhost:3000/admin/video/edit/5 and the controller looks like this
albumEdit: async (req, res) => {
const editInfoId = req.params.id;
await Movie.findOne({ where: { id: editInfoId } }).then((movie) => {
if (movie) {
res.render('admin/movies/edit', { title: 'Edit Movie On Page One', movie });
}
});
},
for the testing purpose when I type the wrong id after edit/ then the process is freezing after some time I am getting 500 errors.
how to prevent this if someone tries to break my app with the wrong id in the URL? I want something like if anyone tries to do this application redirect to an error page.
I am new in node js express js I need some info.
Your route will freeze if movie is falsy or if fineOne results in an error because for both of these cases you don't send any response.
after some time I am getting 500 errors.
If you run your node server behind a web server then this 500 is due to a timeout because your router does not send a response.
how to prevent this if someone tries to break my app with the wrong id in the URL? I want something like if anyone tries to do this application redirect to an error page.
As with any programming language or code, make sure you handle all control flows and possible exceptions.
Besides that, if you use await you in most of the cases don't want to use .then.
albumEdit: async (req, res) => {
const editInfoId = req.params.id;
try {
let movie = await Movie.findOne({
where: {
id: editInfoId
}
})
if (movie) {
res.render('admin/movies/edit', {
title: 'Edit Movie On Page One',
movie
});
} else {
// either the if is not necessary or you have to also handle the else cases
// send some error response
res.send('error')
}
} catch (err) {
// send some error response
res.send('error')
}
}
For completeness, this is how where you would need to do changes in your code, but as said above don't mix await and then:
albumEdit: async (req, res) => {
const editInfoId = req.params.id;
try {
await Movie.findOne({
where: {
id: editInfoId
}
}).then((movie) => {
if (movie) {
res.render('admin/movies/edit', {
title: 'Edit Movie On Page One',
movie
});
} else {
// either the if is not necessary or you have to also handle the else cases
// send some error response
res.send('error')
}
});
} catch (err) {
// send some error response
res.send('error')
}
}
I just got a problem with my server NodeJS. I think it has to do with await/async
What I want to do is making a system that use Socket to create Email (with nodemailer) from PDF (with puppeteer) and then sending them to an Email adresse.
So I have to create the PDF before sending it by Email.
This is my Code:
async function CreatePDF(){ // Fonction cree
console.log('Trying to make the PDF');
try{
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.setContent('<body><style>' + HeadHTML + '</style>'+ PageHTML + '</body>');
await page.emulateMedia('screen');
await page.pdf({
path: path.join(__dirname, 'Nouveau dossier', NumberOfTheFile + '.pdf'),
format: "A4",
printBackground: true
});
console.log('PDF Created!');
SendEmail(); //Doesn't use async or await
} catch (e)
{
console.log('Error: ', e)
}
}
function SendEmail(){
console.log('Trying to send the email');
//Put everything to send Email here.
}
The problem is that the PDF is created after the system try to send the email. I don't know if there is a way to make puppeteer work without await/async or if I can make sure that things go in the correct direction.
On the console i get:
Trying to send the email
...
PDF Created
Before I start the question, I am new in JavaScript, and I have very basic knowledge of async js, but i need to solve this so i can have my first project functional.
I am trying to build a scraping app using Node and Puppeteer. Basically, the user enters a URL ("link" in the code below), puppeteer goes trough the website code, tries to find the specific piece and returns the data. That part I got working so far.
The problem is when a user enters a URL of a site that doesn't have that piece of code. In that case, I get UnhandledPromiseRejectionWarning: Error: Evaluation failed theme is not defined
What do I do so when there is an error like that, I can catch it and redirect the page instead of Getting Internal Server error.
app.post("/results", function(req, res) {
var link = req.body.link;
(async link => {
const browser = await puppeteer.launch({ args: ['--no-sandbox'] })
const page = await browser.newPage()
await page.goto(link, { waitUntil: 'networkidle2'})
const data = await page.evaluate('theme.name');
await browser.close()
return data
})(link)
.then(data => {
res.render("index", {data: data, siteUrl: link});
})
})
You can extend the async part to the whole route handler and do whatever you want on catch:
app.post('/results', async (req, res) => {
try {
const link = req.body.link
const browser = await puppeteer.launch({ args: ['--no-sandbox'] })
const page = await browser.newPage()
await page.goto(link, { waitUntil: 'networkidle2'})
const data = await page.evaluate('theme.name')
await browser.close()
res.render("index", {data: data, siteUrl: link})
} catch(e) {
// redirect or whatever
res.redirect('/')
}
});
i have a node server. I pass a Url into request and then extract the contects with cherio. Now what im trying to do is detect if that webpage is using google analytics. How would i do this?
request({uri: URL}, function(error, response, body)
{
if (!error)
{
const $ = cheerio.load(body);
const usesAnalytics = body.includes('googletag') || body.includes('analytics.js') || body.includes('ga.js');
const isUsingGA = ?;
}
}
From the official analytics site, they say that you can find some strings that would indicate GA is active. I have tried scanning the body for these but they always return false even if that page is running GA. I included this in the code above.
Ive looked at websites that use it and I cant see anything in their index that would suggest they are using it. Its only when i go to their sources and see they are using it. How would i detect this in node?
I have Node script which uses Puppeteer to monitor the requests sent from a website.
I wrote this some time ago so some parts might be irrelevant to you but here you go:
'use strict';
const puppeteer = require('puppeteer');
function getGaTag(lookupDomain){
return new Promise((resolve) => {
(async() => {
var result = [];
const browser = await puppeteer.launch({ headless: true });
const page = await browser.newPage();
await page.setRequestInterception(true);
page.on('request', request => {
const url = request.url();
const regexp = /(UA|YT|MO)-\d+-\d+/i;
// look for tracking script
if (url.match(/^https?:\/\/www\.google-analytics\.com\/(r\/)?collect/i)) {
console.log(url.match(regexp));
console.log('\n');
result.push(url.match(regexp)[0]);
}
request.continue();
});
try {
await page.goto(lookupDomain);
await page.waitFor(9000);
} catch (err) {
console.log("Couldn't fetch page " + err);
}
await browser.close();
resolve(result);
})();
})
}
getGaTag('https://store.google.com/').then(result => {
console.log(result)
})
Running node ga-check.js now returns the UA ID of the Google Analytucs tracker on the lookup domain: [ 'UA-54090495-1' ] which in this case is https://store.google.com
Hope this helps!