PDF is blank when opened - javascript

I've been at this for hours and I'm not getting anywhere. I'm trying to download a PDF file from my server. I'm currently running this on localhost. When I open the PDF the PDF is a white blank page. Can someone please let me know what I'm missing. I've checked the PDF saved on the server and it is fine.
App - React, Express.
NPM - Axios, file-saver, html-pdf
Path - Front end React
.then(() =>
axios.get(
'http://localhost:3000/retailers/fetch/pdf',
{
headers: {
'Content-type': 'application/json',
'x-auth-token': this.props.token
}
},
{ responseType: 'blob' }
)
)
.then((res) => {
console.log('dd', res);
const pdfBlob = new Blob([res.data], { type: 'application/pdf' });
saveAs(pdfBlob, 'newPdf.pdf');
});
Path - Backend express
const options = {
root: path.join(__dirname, '../'),
dotfiles: 'deny',
headers: {
'x-timestamp': Date.now(),
'x-sent': true
}
};
var fileName = 'test.pdf';
res.sendFile(fileName, options, function (err) {
if (err) {
console.log('err', err);
next(err);
}
});

So the answer is simple. responseType: 'blob' was in the wrong place.
axios.get(
'http://localhost:3000/retailers/fetch/pdf',
{
headers: {
'Content-type': 'application/json',
'x-auth-token': this.props.token
},
responseType: 'blob'
}
)

Related

React Native - Sending a PDF with fetch but it is empty

Hey guys I have a question regarding the fetch function from JavaScript and the Package Nodemailer.
NOTE: I am using Expo.
I have a PDF created on my Emulator which looks good (filled with data). Now I want to send this PDF to my Backend and therer I want to send the File out as a PDF and get it in my Mails.
Frontend fetch-Call for my Backend:
async sendMonthReportMail(fileUri) {
await fetch(`${connectionString}/api/mails/sendmonthreport`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
senderUser: "My Name",
recieverMail: "myname#mymail.com",
pathMonthLock: `${fileUri}`
})
})
.then(res => res.json())
.then(res => {
console.log("Success SendMailMonthLock - " + res)
})
.catch(err => console.log("Error SendMailMonthLock - " + err))
}
I have also tried to use formData and change the Content-Type to "application/pdf" but this did not work.
Now my Backend Code looks like this:
router.post("/sendmonthreport", async (req, res) => {
const {recieverMail} = req.body;
const {senderUser} = req.body;
const {pathMonthLock} = req.body;
let transport = nodemailer.createTransport({
host: "mailserver",
port: xx,
secure: false,
tls: {
rejectUnauthorized: false
}
});
var message = {
from: "My Sendermail <sender#mail.com>",
to: `${recieverMail}`,
subject: `Mail comming from - ${senderUser}`,
text: `EmailText `,
attachments:[{
filename: "MyFilename.pdf",
content: __dirname + `./${pathMonthLock}`,
}]
}
await transport.sendMail(message)
.catch(err => console.log("Error Mail: " + err ))
res.send("email send")
})
Now the way that I choose the file.uri is threw the DocumentPicker for Expo.
The Problem I am having now is, that the Mail gets send correctly and there is a PDF attached to it with the correct name. However when I look at the PDF Size it is only 500Bytes and it is completly empty. When trying to open the File that is send via Mail then it tells me that the File is corrupted or wrong format.
How can I send the actual content that is inside the PDF?
When I try to use formData:
async sendMonthReportMail(file) {
fdPost.append("file", file);
fdPost.append("senderUser", "User Name");
fdPost.append("recieverMail", "username#mail.com");
console.log(fdPost);
await fetch(`${connectionString}/api/mails/sendmonthreport`, {
method: "POST",
headers: {
accept: "application/json"
// "Content-Type": "multipart/form-data",
// "Content-Type": "application/json",
// "Content-Type" : "application/pdf"
// "Content-Type": "application/x-www-form-urlencoded"
},
body: fdPost
})
.then(res => res.json())
.then(res => {
console.log("Success SendMailMonthLock - " + res)
})
.catch(err => console.log("Error SendMailMonthLock - " + err))
}
fdPost is defined at the top of my file, console.logging it gives me a valid FormData but the request ends with a Network Error!
Error SendMailMonthLock - TypeError: Network request failed
Also my Backend does not react to that call.
I also tried to use RN Fetch Blob but it only works in React Native only Projects. I am using Expo so this is not a soultion for me!
Edit:
I tried the suggestion in the comments (using Multer):
Frontend:
async sendMonthReportMail(file) {
fdPost.append("file", file);
fdPost.append("senderUser", "name");
fdPost.append("recieverMail", "mail#mail.com");
await fetch(`${connectionString}/api/mails/sendmonthreportTest`, {
method: "POST",
headers: {
Accept: "application/json",
'Content-Type': 'multipart/form-data'
},
body: fdPost
})
.catch(err => console.log("Error SendMailMonthLock - " + err))
}
Backend:
router.post("/sendmonthreportTest", upload.single("file"), (req, res) => {
console.dir(req.file + req.body);
})
Still I have the same issue! It gives me TypeError: Network Error.
Also when I try to call that point with Postman I am getting:
POST /api/mails/sendmonthreportTest 500 6.952 ms - 1221
TypeError: Cannot convert object to primitive value
To confirm my POST Body when I console.log the fdPost before the fetch:
{"_parts":[["file",{"size":69496,"name":"Monatsbericht_User_Name_Dezember2022.pdf","type":"success","uri":"file:///data/user/0/host.exp.exponent/cache/ExperienceData/%2540yxxx%252Fxxx/DocumentPicker/2xx07e4-4136-4b6f-ad70-26xxac64064.pdf","mimeType":"application/pdf"}],["senderUser","User Name"],["recieverMail","user#mail.com"]]}

Is there a way to store locally pdf files from an api response?

I've been trying to save pdf files locally from an api response. Here´s what i´ve tried so far.
const config = {
headers: {
Authorization: `Bearer ${token}`,
responseType: 'blob',
},
};
const response = await axios.get(
apiURL,
config,
);
fs.writeFile(
`filename.pdf`,
response.data,
(err) => {
if (err) return console.log(err);
else console.log('file saved succsefully');
},
);
I don't get any errors, but it doesn't write the file either.
Here is what i get from the response.data
responseType should not be in the headers config.
You could also write the response as a stream to the file using responseType: "stream".
const config = {
headers: {
Authorization: `Bearer ${token}`,
},
responseType: 'stream'
};
const response = await axios.get(apiURL, config)
const fileStream = fs.createWriteStream('filename.pdf')
response.data.pipe(fileStream)
Blob is not a valid data type for fs.writeFile.
Try the following:
const config = {
headers: {
Authorization: `Bearer ${token}`
},
responseType: 'blob'
};
const response = await axios.get(
url,
config
);
const arrayBuffer = await response.data.arrayBuffer();
const buffer = Buffer.from(arrayBuffer);
const filePath = `./${response.headers['content-disposition'].split('=')[1]}.pdf`;
await fs.writeFile(filePath, buffer).then(() => {
console.log('file saved succsefully');
}).catch((err) => console.log(err));

File Uploading using Node js API

I am really stuck with this issue. I want to upload a file from this API to another API but this code does not seems working when I am sending the form data, it is going as raw content.
form.append('attachment[attachment]', req.files.meeting_attachment);
fetching the data by this way gives source.on is not a function
router.post('/attachments', async (req, res) => {
try {
var form = new FormData();
form.append('meeting_attachment[attachment]', Buffer.from(req.files.meeting_attachment.data), { filename: req.files.meeting_attachment.name });
const options = {
headers: {
'Content-Type': 'multipart/form-data',
'accept': '*/*'
}
};
const url = `https://webhook.site/a307cf34-at22-70b4-3a84-7ef36062d72c`;
const response = await axios.post(url, form, options).then((res) => {
console.log("result", res);
});
res.json({ status: true, data: response.data });
} catch (err) {
console.log("err", err);
res.status(404).json({ status: false, error: 'File type is not supported' });
}
});
I am getting 400 Bad Request with this raw content
Postman request to the actual receiver API looks like this on webhoook and it uploaded the file successfully.

Getting file from azure storage and sending it via Post method throw error but works with local files

I have made a request to server via post method.
It's working when file is on local
Here's the request working
var options = {
'method': 'POST',
'url':'https://api.powerbi.com/v1.0/myorg/groups/xxxxx/imports?datasetDisplayName=test',
'headers': {
'Content-Type': 'multipart/form-data',
'Authorization': `Bearer ${tokenResponse.accessToken} `
},
formData: {
'': {
'value': fs.createReadStream('/Users/userName/Downloads/file.pbix'),
'options': {
'filename': 'file.pbix',
'contentType': null
}
}
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
Now I would change it to get file from Azure storage
const containerClient = blobServiceClient.getContainerClient('tenants');
const baseUrl = containerClient.url
const blobClient = containerClient.getBlobClient('file/Url/On/AzureBlob')
let blobData
try {
blobData = await blobClient.download(0)
console.log(blobData)
} catch (error) {
console.log(error)
}
var options = {
'method': 'POST',
'url':'https://api.powerbi.com/v1.0/myorg/groups/xxxxx/imports?datasetDisplayName=test',
'headers': {
'Content-Type': 'multipart/form-data',
'Authorization': `Bearer ${tokenResponse.accessToken} `
},
formData: {
'': {
'value': fs.createReadStream('blobData.blobDownloadStream'),
'options': {
'filename': 'file.pbix',
'contentType': null
}
}
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
Here I get an error message from the server ( MS Server )
'{"error":{"code":"UnknownError","pbi.error":{"code":"UnknownError","parameters":{},"details":[],"exceptionCulprit":1}}}'
I guess that the error came from the way I download file and sent it to the server.
Is there a way to get the same file type/format as fs.createReadStream for AzureBlobClient ?
You should specify a file path for fs.createReadStream(some path), but in your second scenario, you provided a string that not a valid file path.
So basically,if you want to use fs.createReadStream in your code, you should download the file to local as a temp file and then upload it. Try code below :
const fileName = "blob Name"
const containerClient = blobServiceClient.getContainerClient('tenants')
const blobClient = containerClient.getBlobClient(fileName)
const tempFilePath = "/some local temp path/" + fileName
blobClient.downloadToFile(tempFilePath).then(function(){
console.log("file downloaded")
var options = {
'method': 'POST',
'url':'https://api.powerbi.com/v1.0/myorg/groups/xxxxx/imports?datasetDisplayName=test',
'headers': {
'Content-Type': 'multipart/form-data',
'Authorization': `Bearer ${tokenResponse.accessToken} `
},
formData: {
'': {
'value': fs.createReadStream(tempFilePath),
'options': {
'filename': 'file.pbix',
'contentType': null
}
}
}
};
request(options, function (error, response) {
if (error) throw new Error(error);
console.log(response.body);
});
//remove temp file after upload
fs.unlinkSync(tempFilePath)
})

React Native Failed Upload Image

I am struggling from the past 2 days to crack the file/image upload with React Native to MongoDB. I literally read all the related forums but there is no luck. I read couple of forums and they gave a sample example but I wasn't succeeded. Here are the sample codes that I wrote.
Client Side :
const { uri } = await this.camera.takePictureAsync(options);
let formData = new FormData();
formData.append('file', {
uri: uri.replace("file:///", ""),
type:'image/jpg', name:'userProfile.jpg',
});
const rawResponse = await fetch('http://192.168.1.5:9000/api/contrats/upload', {
method: 'POST',
body: formData,
headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data; charset=utf-8',
},
});
const content = await rawResponse.json();
console.log(content);
Server Side
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, __basedir + '/resources/static/assets/uploads');
},
filename: (req, file1, cb) => {
console.log("file : ", file);
let name = file.originalname || file.name;
let extension = name.substr((~-name.lastIndexOf(".") >>> 0) + 2);
let filename = generateId() +"."+ extension; nsion;
cb(null, filename)
},
});
var upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5
}
});
Result
Try out the below
let body = new FormData();
let filename = uri.split('/').pop();
body.append('file', {uri:uri, name:filename, type:'image/jpg', });
const header = {
'Accept': 'application/json',
'content-type': 'multipart/form-data',
}
fetch("http://192.168.1.5:9000/api/contrats/upload", {
method: 'POST',
headers: header,
body:body,
}).then(response => response.json())
.then(res => console.log(res))
.catch(err => console.log("err", err)

Categories

Resources