I have simple app.js for Node.js under localhost:3000
app.js:
let http = require('http');
http.createServer((req, res) => {
res.writeHead(200);
let response;
if(~req.url.indexOf('post')) {
response = req.body.content;
} else {
response = '<script src="http://localhost/fetch.js"></script>';
}
res.end(response);
}).listen(3000);
The file fetch.js is placed on my another local server and is successfully enqueued to the page
fetch.js:
read('http://localhost:3000/?post').then((response) => {
console.log(response);
});
async function read(url) {
const response = await fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8',
},
body: JSON.stringify({
content: 'Text'
})
});
return response.text();
}
So I render HTML with fetch.js which then send POST request to the same page, but with a query ?post
However, when I run node app.js I get the error
Can not read property 'content' of undefined
So I don't get req.body
Why and how to resolve?
i think you are missing parser for your http server, there is no body because you actually didn't parse the body.
assemble the chunks like below then parse it as the header sais.
this is my work for myself
private parseBody(req: IncomingMessage) {
return new Promise((resolve, reject) => {
const chunks: any[] = []
req.on("data", (chunk) => {
chunks.push(chunk)
})
req.on("end", () => {
const data = Buffer.concat(chunks)
switch (req.headers["content-type"]) {
case "application/json":
resolve(this.parseJson(data.toString()))
break
case "application/x-www-form-urlencoded":
resolve(this.parseUrlEncoded(data.toString()))
break
default:
resolve({})
}
})
})
http server is very abstract and doesn't support anything basicly, i suggest using express or fastify.
working example: https://frontendguruji.com/blog/how-to-parse-post-request-in-node-js-without-expressjs-body-parser/
this is the class im using
http.resolver.ts
private parseJson(data: string) {
return JSON.parse(data)
}
private parseUrlEncoded(data: string) {
const parsedData = new URLSearchParams(data)
const dataObj: any = {}
for (var pair of parsedData.entries()) {
dataObj[pair[0]] = pair[1]
}
return dataObj
}
private parseBody(req: IncomingMessage) {
return new Promise((resolve, reject) => {
const chunks: any[] = []
req.on("data", (chunk) => {
chunks.push(chunk)
})
req.on("end", () => {
const data = Buffer.concat(chunks)
switch (req.headers["content-type"]) {
case "application/json":
resolve(this.parseJson(data.toString()))
break
case "application/x-www-form-urlencoded":
resolve(this.parseUrlEncoded(data.toString()))
break
default:
resolve(parse(req.url ?? "/", true).query)
}
})
})
}
you may use await behind the parseBody function after
Ok, thanks to @Fide. The link he posted has the answer:
let http = require('http');
http.createServer((req, res) => {
if(~req.url.indexOf('post')) {
let body;
req.on('data', function(data) {
body = data;
})
req.on('end', function() {
res.writeHead(200);
res.end(body);
})
} else {
res.writeHead(200);
res.end('<script src="http://localhost/fetch.js"></script>');
}
}).listen(3000);