Error when using fetch method and NodeJs route [closed] - javascript

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 days ago.
Improve this question
I got an issue using fetch method in JavaScript with a NodeJS routing.
My JS code :
fetch(url, {
method: 'POST',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
credentials: 'same-origin',
body: JSON.stringify({ ids: arrayIds })
}).then(function(response) {
return response.json();
}).then(function(data) {
if (data.reload) {
document.location.reload();
} else if (data.url) {
document.location.href = data.url;
}
});
My NodeJS route :
function _postMultiplePrint(request, response) {
var fonts = {
Roboto: {
normal: 'public/fonts/OpenSans-Regular.ttf',
bold: 'public/fonts/OpenSans-Bold.ttf',
italics: 'public/fonts/OpenSans-Italic.ttf',
bolditalics: 'public/fonts/OpenSans-BoldItalic.ttf'
}
},
printer = new PdfPrinter(fonts),
docDefinition, pdfDoc;
docDefinition = {
content: [
{
text: 'This paragraph fills full width, as th'
}
],
pageSize: 'A4',
pageMargins: [72, 72],
footer: {},
background: {}
};
pdfDoc = printer.createPdfKitDocument(docDefinition);
response.setHeader('Content-type', 'application/pdf');
response.setHeader('Content-disposition', 'inline; filename="book.pdf"');
pdfDoc.pipe(response);
pdfDoc.end();
response.send(JSON.stringify({ reload: false, url: '' }));
}
My issue : my book.pdf is not loaded in the page when I'm not using fs to write it.
It works with this code but I write files on the server and I don't want to do that :
function _postMultiplePrint(request, response) {
var fonts = {
Roboto: {
normal: 'public/fonts/OpenSans-Regular.ttf',
bold: 'public/fonts/OpenSans-Bold.ttf',
italics: 'public/fonts/OpenSans-Italic.ttf',
bolditalics: 'public/fonts/OpenSans-BoldItalic.ttf'
}
},
printer = new PdfPrinter(fonts),
docDefinition, pdfDoc;
docDefinition = {
content: [
{
text: 'This paragraph fills full width, as th'
}
],
pageSize: 'A4',
pageMargins: [72, 72],
footer: {},
background: {}
};
pdfDoc = printer.createPdfKitDocument(docDefinition);
pdfDoc.pipe(fs.createWriteStream('./public/uploads/book.pdf'));
pdfDoc.end();
response.send(JSON.stringify({ url: '/uploads/book.pdf' }));
}

Each HTTP request can have one and only one response.
Your JS makes an HTTP request. Your server-side code then tries to response with PDF (response.setHeader('Content-type', 'application/pdf'); response.setHeader('Content-disposition', 'inline; filename="book.pdf"'); pdfDoc.pipe(response); pdfDoc.end();) and JSON (response.send(JSON.stringify({ reload: false, url: '' }));).
That's two responses. That won't work.
What's more, the Content-disposition will be ignored because it is a request initiated by Ajax, not by regular browser navigation.

The first backend code is fine, it's just not compatible with the frontend. Here's a full working example
backend
pdfDoc = printer.createPdfKitDocument(docDefinition);
response.setHeader('Content-type', 'application/pdf');
response.setHeader('Content-disposition', 'inline; filename="book.pdf"');
pdfDoc.pipe(response);
pdfDoc.end();
// The below code must be remove
// since the response has been sent by pdfDoc.pipe(response);
// response.send(JSON.stringify({ reload: false, url: '' })); // <- remove this line
Frontend if your route is POST method
const form = document.createElement("form");
// Define your route here
form.setAttribute("action", "http://localhost:8000");
form.setAttribute("method", "POST");
const btn = document.createElement("button");
btn.setAttribute("type", "submit");
form.appendChild(btn);
document.body.appendChild(form);
btn.click();
Frontend if your route is GET method
window.open("http://localhost:8000");

Related

File upload Angular 8 with application/octet-stream - Binary

I have an api that expects to receive an image with "application/octet-stream", I currently have a "ng2-file-upload" library, I would like to make it work with it but if it is not possible I could try with another one or just Even angular.
Currently my code looks like this:
constructor(
) {
const bearer = 'Bearer ' + this.authService.getToken();
this.uploadImageNewsletter = new FileUploader({
url: `https://myapi/upload?extension=jpg`,
autoUpload: true,
method: 'post',
isHTML5: true,
allowedMimeType: ['application/octet-stream', 'image/png', 'image/jpg', 'image/jpeg', 'image/gif'],
allowedFileType: ['application/octet-stream', 'image', 'pdf'],
// disableMultipart: false,
headers: [
{
name: 'Authorization',
value: bearer
},
{
name: 'Content-Type',
value: 'application/octet-stream'
}
]
});
this.uploadImageNewsletter.onProgressAll = () => {
this.loading = true;
};
this.uploadImageNewsletter.onCompleteItem = (item: FileItem) => {
item.remove();
this.loading = false;
};
}
With postman I can upload with the following settings:

Javascript Fetch API: header params not working

This is my sample request:
var header = new Headers({
'Platform-Version': 1,
'App-Version': 1,
'Platform': 'FrontEnd'
});
var myInit = {
method : 'GET',
headers: header,
mode : 'no-cors',
cache : 'default'
}
fetch('http://localhost:3000/api/front_end/v1/login', myInit)
.then(res => {
console.log(res.text())
})
When I debug, I see that this request is sent successfully to server, but server hasn't received header params (in this case is Platform-Version, App-Version and Platform). Please tell me which part do I config wrong.
thanks
You are using it correctly, but you have to tell your backend service to allow custom headers (X-). For example, in PHP:
header("Access-Control-Allow-Headers: X-Requested-With");
Also, your custom headers should be prefixed with X-. So you should have:
'X-Platform-Version': '1'
And one last thing, your mode needs to be cors.
You can see that standard headers are being sent with the following code. take a look at the network tab to see the standard request headers.
var header = new Headers();
// Your server does not currently allow this one
header.append('X-Platform-Version', 1);
// You will see this one in the log in the network tab
header.append("Content-Type", "text/plain");
var myInit = {
method: 'GET',
headers: header,
mode: 'cors',
cache: 'default'
}
fetch('http://localhost:3000/api/front_end/v1/login', myInit)
.then(res => {
console.log(res.text())
});

Trying to GET from api after posting API issues

Hi developers I am back again with a question,
I am trying to get some data from this website https://www.iamsterdam.com/nl/uit-in-amsterdam/uit/agenda. First did I crawl the website but when doing that it came to mind that they have a api and that will be a lot faster. So I tried to get the data from the api I tried this:
get-website.js:
var webPage = require('webpage');
var page = webPage.create();
var settings = {
operation: "POST",
encoding: "utf8",
headers: {
"Content-Type": "application/json"
},
data: JSON.stringify({
DateFilter: 03112016,
PageId: "3418a37d-b907-4c80-9d67-9fec68d96568",
Take: 2,
Skip: 12,
ViewMode: 1
})
};
page.open('https://www.iamsterdam.com/api/AgendaApi/', settings, function(status) {
console.log(page.content);
phantom.exit();
});
get-website.php
$phantom_script= 'get-website.js';
$response = exec ('phantomjs ' . $phantom_script);
echo $response;
But what I get back doesn't look good:
Message":"An error has occurred.","ExceptionMessage":"Page could not be found","ExceptionType":"System.ApplicationException","StackTrace":" at Axendo.SC.AM.Iamsterdam.Controllers.Api.AgendaApiController.GetResultsInternal(RequestModel requestModel)\r\n at lambda_method(Closure , Object , Object[] )\r\n
etc.
Here is a picture of firebug:
I hope someone can help me.
Interesting question. I was a bit surprised that the site would honor AJAX-request in a browser and even in cURL, but not in PhantomJS. In such cases you have to study and replicate request very carefully, because one of little details probably greatly affects the server's response.
Turned out, it was a cookie and form content-type that had to be set accordingly.
var webPage = require('webpage');
var page = webPage.create();
// courtesy of http://stackoverflow.com/a/1714899/2715393
var serialize = function(obj) {
var str = [];
for(var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
}
var settings = {
operation: "POST",
encoding: "utf8",
headers: {
"accept-encoding" : "identity", // https://github.com/ariya/phantomjs/issues/10930#issuecomment-81541618
"x-requested-with" : "XMLHttpRequest",
"accept-language" : "en;q=0.8,en-US;q=0.6",
"authority" : "www.iamsterdam.com",
"accept":"application/json, text/javascript, */*; q=0.01",
"content-type" : "application/x-www-form-urlencoded; charset=UTF-8",
"cookie" : "website#lang=nl"
},
data: serialize({
Genre: '',
DateFilter: '03112016',
DayPart: '',
SearchTerm: '',
Neighbourhoud: '',
DayRange: '',
ViewMode: 1,
LastMinuteTickets : '',
PageId: '3418a37d-b907-4c80-9d67-9fec68d96568',
Skip: 0,
Take: 12
})
};
page.open('https://www.iamsterdam.com/api/AgendaApi/', settings, function(status) {
console.log(page.content);
phantom.exit();
});

Posting multiple Photos to one post

I have been trying to create an application which needs multiple photos to be attached to one post. These are the following attempts i tried,
First i used facebook-node-sdk which JS SDK to achieve different functionality, but Official Js Sdk does't have option for file to upload, when then i moved to attaching/inserting photo itself to HTTP POST with the help of form-data, with the following code-
var form = new FormData();
form.append('file', fs.createReadStream(picPaths[0]));
form.append('message', "Hello"); //Put message
var ACCESS_TOKEN = "ACCESS_TOKEN";
var options = {
method: 'post',
host: 'graph.facebook.com',
path: '{Object-ID}/photos' + '?access_token=' + ACCESS_TOKEN,
headers: form.getHeaders(),
}
var request = https.request(options, function(res) {
console.log(res, false, null);
});
form.pipe(request);
request.on('error', function(error) {
console.log(error);
});
This works with one photo.
But as you can see in this github.com/Thuzi/facebook-node-sdk/issues/113 which i started, it is not possible to attach more than one photo.
So as mentioned by dantman i stated looking in batch process, which can be found developers.facebook.com/docs/graph-api/making-multiple-requests titled under Uploading binary data. The one thing that hits and give me hope is this one statement.
The attached_files property can take a comma separated list of attachment names in its value.
Note That (batching with photos) also is not possible with this library or JS SDK (Please correct me if i am wrong)
You can do post images with curl like this,
curl -F 'access_token=ACCESS_TOKEN' -F 'batch=[{"method":"POST","relative_url":"{Object-Id}/photos","body":"message=Test Post","attached_files":"file1"}]' -F 'file1=#image1' -F 'file2=#image2' https://graph.facebook.com
The above code posts with one image
So my question is this, it possible to attach multiple images/binary_files to the post with the help of curl, something like ..."attached_files":"file1,file2"... as suggested by docs, please help me with this problem and if you have already done this can you please post the snapshot of your code.
Thanks, Ravi
I finally figured out how.
So first, read the section here titled "Publishing a multi-photo post with uploaded photos": https://developers.facebook.com/docs/graph-api/reference/page/photos/#Creating
What it says is basically correct, however, it is not in JavaScript. Also, they don't emphasize enough an important step: You have to set "published" to "false" for the image you upload, for it to then be attachable to the post that gets created.
So anyway, here is the working code -- in JavaScript, and with "published" correctly set to false:
async function PostImageToFacebook(token, filename, mimeType, imageDataBlob, message) {
var fd = new FormData();
fd.append("access_token", token);
fd.append("source", imageDataBlob);
//fd.append("message", "photo message for " + filename);
fd.append("no_story", "true");
//fd.append("privacy", "SELF");
fd.append("published", "false");
// Upload image to facebook without story(post to feed)
let uploadPhotoResponse = await $.ajax({
url: "https://graph.facebook.com/me/photos?access_token=" + token,
type: "POST",
data: fd,
processData: false,
contentType: false,
cache: false
});
console.log(`Uploaded photo "${filename}": `, uploadPhotoResponse);
let uploadPhotoResponse2 = await $.ajax({
url: "https://graph.facebook.com/me/photos?access_token=" + token,
type: "POST",
data: fd,
processData: false,
contentType: false,
cache: false
});
console.log(`Uploaded photo "${filename}": `, uploadPhotoResponse2);
let makePostResponse = await $.ajax({
"async": true,
"crossDomain": true,
"url": "https://graph.facebook.com/v2.11/me/feed",
"method": "POST",
"headers": {
"cache-control": "no-cache",
"content-type": "application/x-www-form-urlencoded"
},
"data": {
"message": "Testing multi-photo post2!",
"attached_media[0]": `{"media_fbid":${uploadPhotoResponse.id}}`,
"attached_media[1]": `{"media_fbid":${uploadPhotoResponse2.id}}`,
"access_token": token
}
});
console.log(`Made post: `, makePostResponse);
}
The code above currently just uploads the same image twice, then attaches both to the new post. Obviously, in real world usage you would replace the data in the second photo-upload with a different image.
Anyway, to use the function, just call it like so:
function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(",")[1]);
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ab], {type: "image/png"});
}
let imageDataURI = GetImageDataURIFromSomewhere();
let imageBlob = dataURItoBlob(imageDataURI);
PostImageToFacebook(fbToken, "some_filename", "image/png", imageBlob, window.location.href);
this is possible.
Note: This one is not an efficient way to do this but just for explaining purpose i am doing here,
The first hint that i got that it may be possible is from this post
Steps that i used:
Follow the doc to create custom open graph stories
Let's suppose you four image to attach (pic[1, 2, 3, 4])
First i staged them with the help of new facebook-node-sdk v1.1.0-alpha1 with the code something like this (with batch process).
FB.api( "", "post", {
batch: [
{
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file1",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file2",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file3",
type:"image/png"
}, {
method: "POST",
relative_url: "me/staging_resources",
attached_files: "file4",
type:"image/png"
}],
file1: fs.createReadStream(picPaths[0]),
file2: fs.createReadStream(picPaths[1]),
file3: fs.createReadStream(picPaths[2]),
file4: fs.createReadStream(picPaths[3])
},
function(response) {
console.log(response);
});
Now from the response part get the url and dis the post with the same library. With the code something like this.
FB.api(
"me/objects/{app-namespace}:{custom-object}",
"post", {
"object": {
"og:title": "Sample Post",
"og:image[0]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[1]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[2]": {
"url": "fbstaging:{...}",
"user_generated": true
},
"og:image[3]": {
"url": "fbstaging:{...}",
"user_generated": true
}
}
},
function(response) {
console.log(response);
}
);
Now, with these two piece of code you will be able to push multiple images/photo to the single post.
Note: this can make more sense or can be done with the help of named batch process which is being described here.
Thanks,
Ravi

Using Facebook's Mobile Hosting API with Parse Cloud Code for App Links

I am having trouble getting App Links working with Parse.
Since my App is mobile only i wanted to use Facebook's Mobile Hosting API.
And since you need to send your Facebook App Secret with the request i wanted to do it with Parse Cloud Code.
All i coud find on the Facebook documentation was how to do it with cURL:
curl https://graph.facebook.com/app/app_link_hosts \
-F access_token="APP_ACCESS_TOKEN" \
-F name="iOS App Link Object Example" \
-F ios=' [
{
"url" : "sharesample://story/1234",
"app_store_id" : 12345,
"app_name" : "ShareSample",
}, ]' \
-F web=' {
"should_fallback" : false, }'
so this is what i came up with in cloud code
Parse.Cloud.httpRequest({
method: 'POST',
url: 'https://graph.facebook.com/app/app_link_hosts',
headers: {
'Content-Type': 'multipart/form-data'
},
body: {
access_token : "APP_ACCESS_TOKEN",
name : "iOS App Link Object Example",
ios : '[{"url" : "sharesample://story/1234","app_store_id" : 12345,"app_name" : "ShareSample",},]',
web : '{"should_fallback" : false,}'
}
the response i get is: Request failed with response code 400
now i just read that multipart/form-data is not supported withParse.Cloud.httpRequest
so is there another way to do this?
update: just found out that you can send multipart data with a Buffer,
so this is my code now
var Buffer = require('buffer').Buffer;
var access_token = new Buffer('APP_ACCESS_TOKEN','utf8');
var name = new Buffer('iOS App Link Object Example','utf8');
var ios = new Buffer('[{"url" : "sharesample://story/1234","app_store_id" : 12345,"app_name" : "ShareSample",},]','utf8');
var web = new Buffer('{"should_fallback" : false,}','utf8');
var contentBuffer = Buffer.concat([access_token, name, ios, web]);
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/app/app_link_hosts',
method: 'POST',
headers: {
'Content-Type': 'text/html; charset=utf-8'
},
body: contentBuffer
}
however i am still getting the same result :(
update2: got it working with content type application/x-www-form-urlencoded and normal body. But i think the error was somewhere in my parameters since i tested it with curl and got the same response
It took me a few hours, but I finally got it working:
// Returns the canonical url, like https://fb.me/....
Parse.Cloud.define("createAppLink", function(request, response) {
// see https://developers.facebook.com/docs/graph-api/reference/v2.5/app/app_link_hosts
var storyId = request.params.storyId + ''; // param identifying a single "post"
var appId = 'APP_ID';
var appSec = 'APP_SECRET';
var appToken = appId + '|' + appSec; // your app token
Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/app/app_link_hosts',
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ // you need to stringify it
access_token: appToken,
name: 'LINK TO ' + storyId, // it is needed but not public
android: [{
url: 'app://story/' + storyId, // deep link url
package: 'com.package', // your package name
app_name: 'APP' // your app name
}],
web: { should_fallback: 'false' }
})
}).then(function(httpResponse) {
// We get an id, by which we can fetch
// the canonical url with a get request
var data = JSON.parse(httpResponse.text);
var id = data.id;
return Parse.Cloud.httpRequest({
url: 'https://graph.facebook.com/' + id,
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
params: {
access_token: appToken,
fields: 'canonical_url',
pretty: 'true'
}
});
}).then(function(httpResponse) {
var data = JSON.parse(httpResponse.text);
var canonicalUrl = data.canonical_url;
response.success(canonicalUrl);
}, function(error) {
response.error(error);
})
});

Categories

Resources