I try to download a file using nodejs and Javascript.
When I call the URL in the Browser, the file gets downloaded.
When I call this Endpoint in my javascript file using fetch, the download doesn't work
NodeJS Endpoint
app.get("/download", function (req, res, next) {
res.download(
filepath
);
});
Javascript Call
const downloadFile = async (path) => {
await fetch("http://localhost:8080/download", {
method: "Get",
})
.then((response) => {
console.log(response);
})
.catch((error) => {
console.log(error);
});
};
Do you have any suggestions?
Thank you very much!
When you make a request using Ajax then the response is passed back to the JavaScript code for handling.
If you want to do something with the file the server has sent you, then you need to write JavaScript to do something with it.
Your JavaScript logs the response object then stops.
The browser will only automatically render it in the viewport / save it to downloads if you type the URL into the address bar / click a link / etc. Doing Ajax explicitly avoids that automatic handling.
So the solution here is: Don't use Ajax. Use a link, or assign a value to location, etc.
Related
I have input type='text' where a user will provide hyperlink for google docs to be downloaded, like this
"https://docs.google.com/spreadsheets/d/1w_qYEgD5w-xIrnMpRMmeUycZBJiAfo4zxlVTkXb8LU4/export?gid=1865948320&format=csv"
When I pass this string as href for link with download parameter it prompts save as window and save file in csv format. If you follow the mentioned link above it will trigger file download. My goal is to save data on the client-side without "Save as" window and work with csv data. Any suggestions on how to implement this? Appreciate any help.
In fact, on the client-side I have an input where the user provides docs.google link on a specific document with predefined csv format and I send this link to my local server on express. On the local server I make axios get request, function looks like this
// Request from client where I send url link
app.post("/upload", (req, res) => {
// Handle get request with link provided from client/front
axios(req.body.payload, { method: "GET" })
.then((response) => {
res.status(200);
// Data represents string of characters that I send back to client and
// and in my case populate table
res.json({ file: response.data });
})
.catch((error) => {
res.status(404);
res.send(error);
});
});
As the title says, i have a part of my react app that tries to get some data from my database, making a select based on the value I passed to it. So im gonna go ahead and first show the code where i think the problem lies:
So first, this is the function from one of my forms that sends the request to the server, i know code is probably ugly, but i can tell from the console.logs that the parameters im sending are what i intend to send(a string called "licenciaInput"
async handleClickLicencia (event) {
event.preventDefault();
console.log(this.state);
console.log("licenciaInput: "+this.state.licenciaInput);
const datoBuscar = this.state.licenciaInput;
axios.get('http://localhost:3001/atletas/:licencia',this.state)
.then(response =>{
console.log(response)
})
.catch(error =>{
console.log(error)
})
And then, i have this function which is called in that localhost route which attempts to get "licencia", and launch a select in my postgresql db where licencia="whatever", you can see the sentence in the code:
const getAtletasByLicencia = (request, response) => {
const licencia = request.body.licenciaInput;
console.log("Request: "+request);
console.log("what the server gets: "+licencia);
// const licencia = request.licenciaInput;
const sentencia ="SELECT * FROM atleta WHERE licencia ='"+licencia+"'";
pool.query(sentencia, (error, results) =>{
if(error){
throw error
}
response.status(200).json(results.rows)
})
}
As you can see, i have console.logs everywhere, and i still cannot access whatever element i send, because i always get on the server console "undefined" value.
TLDR:How can i access the "licenciaInput" i passed from my client form to my server, i have tried request.body.licenciaInput, request.params.licenciaInput, and request.licenciaInput, but none of those seem to work
I also know i have to treat after that the data i receive from the server, but i need to solve this before looking two steps ahead. Im also really new to React and node/express, so feel free to burn me with good practices im not meeting.Thanks in advance
EDIT: Im also adding this code that i have which shows the route for my method in the server:
app.get('/atletas/:licencia', db.getAtletasByLicencia)
As #Gillespie59 suggested that i should send a POST request, but i dont think i should if im both trying to send a parameter to the server to make a select, and then send the results back to the client
Change your request to:
axios.get(`http://localhost:3001/atletas/${this.state.licenciaInput}`)
...
and your route (if you are using express) should look like this:
app.get('/atletas/:licencia', function (req, res) {
var licencia = req.params.licencia
...
})
As you are using request.body you should send a POST request with axios and add a body.
I send an image file to my node server via my react app -
I want to host these images on google cloud or similar so they have an accessible URL.
I have tried using cloudinary and google cloud but to no avail thus far!
My react-side code (shortened):
imageFile = this.state.files[0])
const formData = new FormData()
formData.append('file', imageFile);
sendImage(formData)
sendImage(image) {
axios.post("https://137a6167.ngrok.io/image-upload", image, {
})
.then(res => { // then print response status
console.log(res.statusText)
})
}
The file is successfully sent to my server and consoled:
app.post('/image-upload', (req, res) => {
console.log('consoling the req.body!!!!' + JSON.stringify(req.body))
})
THE CONSOLE: consoling the req.body!!!!{"1":"[object File]"}
I did try use this following cloudinary method, yet it threw errors:
cloudinary.config({
cloud_name: process.env.CLOUD_NAME,
api_key: process.env.API_KEY,
api_secret: process.env.API_SECRET
})
app.use(formData.parse())
app.post('/image-upload', (req, res) => {
const values = Object.values(req.files)
const promises = values.map(image => cloudinary.uploader.upload(image.path))
Promise
.all(promises)
.then(results => res.json(results))
})
this gave me the error that an unhandled error in the promise wasnt handled and i got a bit lost with where to go beyond that!
I looked at google cloud storage too but couldn't get it working! Any advice?
What I really want to do is return back to my react app the URL of the hosted image - so it can be stored in DB for the user!
If you can help at all that would be greatly appreciated, thank you.
There are couple of things you need to fix on the front end before you try to upload to any cloud.
First you need to set 'Content-Type': 'multipart/form-data' header in axios to send the file data properly.
Check this thread for more details: How do I set multipart in axios with react?
Then on the express side you need multer or some other similar library to receive the data. You can't access it from req.body. multer adds req.files for example.
https://github.com/expressjs/multer
Try there steps and then post the exact error message you are receiving from google cloud.
Sorry, I tend to be a bad writer when I have not fully woken up, let me revise.
I am using expressjs with passportjs (local strategy) to manage my server and using connect-busboy to manage file uploading. I do not think passport will play a role in this.
Here is the server code for managing file uploads:
app.post('/upload', isLoggedIn, (req, res) => {
if(req.busboy){
req.pipe(req.busboy);
req.busboy.on('file', (fieldname, file, filename, encoding, mimetype) => {
if(mimetype.match(/^image\//)){
var root = path.join(__dirname, "../public/images/");
if(fs.existsSync(path.join(root, filename))){
var name = getUnique(path.join(root, filename));
} else {
var name = filename;
}
var ws = fs.createWriteStream(path.join(root, name), { flags: "a" });
file.pipe(ws);
}
});
}
});
As for my client page, it is used to change a JSON object which will get re-uploaded to the server as a configuration tool. When I upload a new image asynchronously I need to get the filename to update this JSON object while working on it. For uploading from the clients end I am using dropzonejs, which did not require any configuration on my part to work.
So, in summary I upload a number of images via dropzone asynchronously, busboy and fs on my server save the file, and I would like to get the filename returned to my javascript to modify the existing JSON object.
Edit solution:
Thanks to Elliot Blackburn for pointing me in the right direction.
By calling:
ws.on('close', () => {
res.send({filename: name});
});
after file.pipe(ws); to send the response back to the client. On the client side modify dropzone to handle the response like so:
dropzone.on('success', (file, res) => {
console.log(res);
});
Just send it in the normal http response. It'll depend what library you're using but most will allow you to trigger a normal req, res, next express call. From that you can access the file object, and return anything you want.
Something like:
req.send({filename: name}); // name is the filename var set earlier in the code.
Once you've finished editing the file and such, you can get the name and put it into that returned object and your client will receive that as object as the response which you can act upon.
I've got a simple node.js + Restify backend with standard CORS settings and this endpoint:
var file = '1,5,8,11,12,13,176,567,9483';
server.get('/download', function(req, res, next) {
res.set({"Content-Disposition": "attachment; filename='numbers.csv'"});
res.setHeader("Content-type", "text/csv");
res.send(file);
return next();
}, function(err) {
res.send(err);
});
What it's suppose to do is to is to create CSV file and return it.
It works great when I simply type in the endpoint address to web browser and hit enter. The file gets downloaded properly.
But when I try to do the same thing, but instead of using browser's address bar I use Restangular like that:
Restangular.one('download').get().then(function (res) {
console.log(res);
});
it just writes response to console, but no file is being downloaded.
Is there a way to do this using Restangular? Or maybe I need to use something else for this?
I am not sure if Restangular can do that, but I am using FileSaver script for stuff like that. Add Filesaver to your HTML head and then:
Restangular.one('download').get().then(function (res) {
var file = new Blob([res], { type: 'text/csv' });
saveAs(file, 'something.csv');
});