I am sending a base64 string to my node.js server. But its adding the string inside object brackets {}
Front-end code:
I encode the base64 string to preserve it.
let options = {
headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
};
let encodedImage = encodeURIComponent(body);
return this._http.put<IUser>(`${BASE_URL}/api/users/${id}/photo`, encodedImage, options)
.map(data => {
return data;
})
.catch(err => {
// do whatever you want when error occurs
console.log(err);
// re-throw error so you can catch it when subscribing, fallback to generic error code
return Observable.throw(err || 'API_ERROR');
});
}
Serverside:
let upload = (req, res) => {
let b64string = req.body;
console.log(b64string);
}
The console log is:
{ 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQA.....+idkVe3H/9k=': '' }
How can I extract the base64 string from within the object so I can access it. it seems like a simple thing but my brain has given up. Any help will be greatly appreciated.
Update:
Update 2:
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
There seems to be something putting your string in an JSON encoded value, hence the {'...' : '...'}.
You could put the base64 encoded string in an json object from the get go, that way you have an expected input when you get the object. You just need to get the string from the json key.
Hope this helps.
The problem here is that you creating a PUT request with
Content-Type : application/x-www-form-urlencoded but you pass a single string as your data. So the body-parser sees this string as a key with an empty value and that's why you get this console log.
So the solution to this,
let options = {
headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
};
let requestBody = new URLSearchParams()
requestBody.append('encodedImage',body)
return this._http.put < IUser > (`${BASE_URL}/api/users/${id}/photo`, requestBody, options)
So we said we have a content type of form-urlencoded (that means all of your data will be passed as giant url query) and we passed a urlencoded form (through the URLSearchParams)
Please bear in mind URLSearchParams browser compatibility.
Please consider using multipart/form-data for your file uploads instead, if you don't have any limitations. The logic of the above will be the same except the new URLSearchParams() will be new FormData().
Related
i have a frontend where I define a string in this case videoLink.
Besides that I have an async function that starts when a button is clicked.
//sveltekit
async function addToQueue(){
console.log(videoLink);
const res = await fetch('/tool/server', {
method: 'POST',
body: {
videoData: videoLink
}
})
const json = await res.json()
console.log(json);
videoLink = "";
}
This function sends an http-post request with fetch to my server.js file.
/** #type {import('#sveltejs/kit').RequestHandler} */
export async function POST(event) {
const data = await event.request.body;
const link = data.videoData;
console.log(link)
}
when i run the post-request (by clicking the Button in my frontend), my server logs undefined. As far as I know the server gets the POST request, because it logs only if I click the button.
But why does it return undefined? I have tried to parse the json, but it didn't work. Can anyone help me? What is wrong with my JSON?
Open the developer tools in your browser. Look at the Network tab. Examine the Request payload you are sending:
[object Object]
fetch doesn't support plain objects for the body option. It will convert them to strings with their toString() method.
You need to either provide:
an object which fetch does support. The common options are
URLSearchParams for application/x-www-form-urlencoded data
FormData for multipart/form-data
an encoded string (such as the output of JSON.stringify) and also set the content-type HTTP request header to match
Which you choose will depend on what encodings the server side code supports.
So I have provided
headers: {
'Content-Type': 'application/json'
}
to fetch the data.
On the server side I've done the following:
export async function POST({request}) {
const data = await request.json()
console.log(data)
return {}
}
Now the function returns {}, which isn't mandatory. The reason it works now is that POST gets {request} as an argument.
Notice the curly braces. Thanks a lot to #Quentin for his help.
I am trying to convert a javascript object array to JSON to pass it with the POST request to the cloud function. However when I use the JSON.parse() function I get an error:SyntaxError: Unexpected token u in JSON at position 0
Can someone tell me what I'm doing wrong, this is my POST request:
const body = `{
"item":[
{"firstName":"John", "lastName":"Doe"},
{"firstName":"Anna", "lastName":"Smith"},
{"firstName":"Peter", "lastName":"Jones"}]
}`;
const init = {
method: 'POST',
body
};
fetch('https://us-central1-web-app-bbo-prod.cloudfunctions.net/TestObject', init)
.then((response) => {
return response.json(); // or .text() or .blob() ...
})
.then((text) => {
// text is the response body
})
.catch((e) => {
// error in e.message
});
and this my cloud function:
exports.TestObject = functions.https.onRequest(async(request, response)=> {
var corsFn = cors();
corsFn(request, response, async function() {
const myJSON = request.body.item;
console.log(JSON.parse(myJSON))
//console.log(item)
})})
TLDR:
Server: remove JSON.parse
Client: change init to
const init = {
method:'POST',
body:JSON.stringify(body),
headers: {
'Content-Type':'application/json'
}
}
Explained:
You've got three issues I see.
Anytime you see the following you are calling JSON.parse on invalid stringified JSON.
SyntaxError: Unexpected token u in JSON at position 0
First, req.body should already be JSON if everything's working properly and you received JSON. To call JSON.parse(req.body.item) is to pass an Object to a function that takes strings. You can just refer to req.body.item.
Second you have to make sure you're sending the correct body, you are passing an object as the body for the fetch function. I'm not familiar with the fetch function but a quick look at the Mozilla examples indicate that should it should be stringified, i.e. body:JSON.stringify(body). The object you pass likely is either converted to form data or has toString() called on it and you're sending [object Object].
// REPL
> ({foo:'bar'}).toString()
'[object Object]'
Third, you have to make sure it gets parsed properly on the backend.
According to the GCloud nodeJS docs the nodejs google cloud functions implement an endpoint for an Express Router.
Normally if you wanted to use JSON the way you are you would need the body parser BodyParser middleware. The examples here (GCloud HTTP Functions) indicate that the body-parser middleware is already instead and working based off of Content-Type header.
Since it's deciding whether to parse it as JSON based on content type you want to set the header in your fetch function as 'content-type':'application/json'.
I create server (node.js / express / boby-parser)
and I need to get array of objects 'users'.
its part of code from server.js file:
let users = [{
name: 'user1',
}];
app.get('/users/', (req, res) => {
const filePath = path.join(pth.dir, 'build', 'index.html');
res.json(users);
res.sendFile(filePath);
});
Its my code from frontend:
const handleResponse = (response) => {
return response.text().then(text => {
const data = text && JSON.parse(text);
if (!response.ok) {
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
return data;
});
};
const getAll = (baseUrl) => {
const requestOptions = {
method: 'GET'
};
return fetch(baseUrl, requestOptions).then(handleResponse);
};
Something wrong with my code at server. (I just dodnt know how to use express server).
when I use getAll function I got JSON text replace my page. Can anyone help? How should I write app.get() in server.js. Or do I need write in server part one app.get() to get page or another app.get() to get JSON data?
Why are you trying to send a file in the response?:
res.sendFile(filePath);
For starters, the response content can either be JSON or a file (or any of a variety of other things of course), but not both. With data like JSON or XML it's possible to combine multiple objects into one larger object for a single response, but this won't work if the content types are entirely different as it is with a file.
Looking at your client-side code, you're not even doing anything with that file. You only read the JSON data:
return response.text().then(text => {
const data = text && JSON.parse(text);
if (!response.ok) {
const error = (data && data.message) || response.statusText;
return Promise.reject(error);
}
return data;
});
So the simplest approach here would just be to not try to send back the file:
app.get('/users/', (req, res) => {
res.json(users);
});
Edit: Based on comments below, you seem to be struggling with the different requests the client makes to the server. The browser loading the page is one request with one response. If that page includes JavaScript that needs to fetch data, that would be a separate AJAX request with its own response containing just that data.
It’s possible to use JSON (or any data) server-side to populate a page template and return a whole page with the data. For that you’d need to use (or build) some kind of templating engine in the server-side code to populate the page before returning it.
The res.json() represents the HTTP response that an Express app sends when it gets an HTTP request. On the other hand, res.sendFile() transfers the file at the given path.
In both cases, the flow is essentially transferred to client who might have made the request.
So no, you cannot use res.sendFile and res.json together.
var options = {
headers: {
'name': 'user1',
}
};
res.sendFile(path.join(__dirname, 'build', 'index.html'), options);
Thats really the closest you can do to achieve the desired task.
I am trying to send multiple objects in the response as json back to client from one route. It is some kind of middleware, that gets called, and then it calls itself another route inside to get the data and do some data processing. Here is the code:
const axios = require('axios');
var datetime = require('node-datetime');
function MiddlewareRoutes(router) {
var MiddlewareController = require('../controllers/MiddlewareController')
router.route('/Middleware/someotherLink/parametres').get(function(req,res,next) {
console.log(req.params.id, req.params.startTime, req.params.endTime);
url = `http://localhost:hidden/link/..`;
url2 = "http://localhost:port+params..."
axios.get(url) //, {responseType: 'json',}
.then(response => {
var formattedData = formatData(response.data);
[max,min] = getMinMax(formattedData);
res.write("max:",max);
res.write("min:",min);
res.write(formattedData);
res.end();
})
.catch(error => {
console.log(error);
});
})
}
However, I am getting the error:
TypeError: First argument must be a string or Buffer
at write_ (_http_outgoing.js:642:11)
at ServerResponse.write (_http_outgoing.js:617:10)
at axios.get.then.response (C:\Users\U500405\Desktop\Backend\routes\MiddleWare.js:19:13)
at <anonymous>
at process._tickCallback (internal/process/next_tick.js:188:7)
What am I doing wrong? I cannot just send strings, because I have to send objects...
Write is for writing strings to the response body, the parameters accepted are (chunk[, encoding][,callback]), however an object is not a string, and your min/max values are not encodings.
As said before, you could use JSON.stringify to convert an object into a JSON string, however since this is pretty common behaviour Express provides a send method that can do exactly that.
res.write(JSON.stringify({
min,
max,
formattedData
}));
or
res.send({
min,
max,
formattedData
});
res.write(formattedData); Here formatted data is a object . As the error message says, write expects a string or Buffer object, so you must convert it. by doing so : res.write(JSON.stringify(formattedData)) . The node expects the content to not to be a object because it needs string to pass on to the server. The server only understands plain text input as mentioned in Nodejs Docs Nodejs Doc Link for res.write() , and by default the encoding is 'utf-8' . so When sending a object through the server , the server discards it and throws an error of expected buffer chunks or string data.
I'm trying to POST data to my server using the fetch API and every time I do I end up with an empty body.
As far as I can tell from the fetch documentation, to post data you need to pass an object with a method key set to "POST" and a body key with a string or FormData object (or some others).
Here's a simple example that is just not working as I would expect:
var formData = new FormData();
formData.append("test", "woohoo");
formData.append("foo", "bar")
// prints out contents of formData to show that it has contents!
formData.forEach(function(key, value) {
console.log(`${key}: ${value}`);
});
fetch("/fetch", {
method: "POST",
body: formData
}).then(function(response) {
return response.json();
}).then(function(json) {
// Logs empty object
console.log(json);
}).catch(function(err) {
console.log(err);
});
I also have an express server on the back of this that logs the request body and echoes it in the response.
app.post("/fetch", function(req, res) {
// Logs empty object :(
console.log(req.body);
res.send(JSON.stringify(req.body));
});
I add the formData as the body of the fetch request, but nothing ever seems to go through.
Please find my test files in this gist here and help!
This is because your node server isn't understanding mulitpart forms correctly (which is what FormData) will send by default.
You can use node-muliparty on your server you can read the form easily without touching the frontend code.
Something like:
var multiparty = require('multiparty');
var app = express();
app.post("/fetch", function(req, res) {
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
console.log(fields);
res.send(JSON.stringify(fields));
});
});
in your index.js will show you it working correctly. There might be a way to make this work with body-parser but I don't know how myself.