I have this problem because I am sending data via JavaScript using XMLHttpRequest but not receiving it in node.js express post method. I don't know what I'm doing wrong.
My script - funcion form execute on window load
function form() {
const btn = document.getElementById("save-data");
let currentPage = window.location.href.split("/").at(-1);
function sendData(data) {
const XHR = new XMLHttpRequest();
XHR.open("POST", window.location.href);
XHR.setRequestHeader("Content-Type", "application/json");
console.log(data); // I get right data
XHR.send(data);
}
btn.addEventListener("click", () => {
switch (currentPage) {
case "settings":
const prefix = document.getElementById("prefix").value;
let buttonState = document.getElementById("module-state");
if (buttonState.hasAttribute("enable")) {
buttonState = "enable";
} else {
buttonState = "disable";
}
sendData({
prefix: prefix,
buttonState: buttonState,
announcements: {
giveawayChannelID: 123,
updateChannelID: 123,
},
});
}
});
}
My Node.js code
router.post('/:id/settings', (req, res) => {
console.log(req.body) // {}
})
Pleas help.
You need to install body-parser package by NPM, and require it in your code
Try
npm i body-parser
Then in your main node script, require it
const bodyParser = require('body-parser');
after that, you should set it as a middleware for express
app.use(bodyParser.json()); //Handles JSON requests
app.use(bodyParser.urlencoded({ extended: false })); //Handles normal post requests
after these steps, you can access values like req.body.value
Related
Here is my frontend JS. As a side note, FormData.append() does not work, so I have to set its properties explicitly. #data is an object with input name: value properties.
function http(data) {
const httpData = new FormData();
for (let prop in data) {
httpData[prop] = data[prop];
}
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState === 4) {
const status = this.status;
const data = this.responseText;
}
};
xhttp.open('POST', '/api/login');
xhttp.setRequestHeader('Content-Type', 'x-www-form-urlencoded');
xhttp.send(httpData);
}
And on the server side
app.use(express.urlencoded({
extended: true
}));
express ready to parse form data, and in the /routes/api.js ( I am using express router )
router.post('/login', (req, res, next) => {
console.log(req.body);
res.end();
});
I got req.body as an {}
Where did I fuck up ?
Here is the working code, courtesy of #Quentin, frontend
function http(data) {
const httpData = new FormData();
for (let prop in data) {
httpData.append(prop, data[prop]);
}
const xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function () {
if (this.readyState === 4) {
const status = this.status;
const data = this.responseText;
}
};
xhttp.open('POST', '/api/login');
xhttp.send(httpData);
}
and backend in /routes/api.js
const formidable = require('formidable');
router.post('/login', (req, res, next) => {
const form = formidable({ multiples: true });
form.parse(req, (err, fields, files) => {
console.log(fields);
res.end();
});
});
You have three problems.
append() does work. It just doesn't store the data in a way that shows up with console.log. Assigning arbitrary properties doesn't work.
You need to send the correct Content-Type header. This is multipart/form-data with a mandatory boundary parameter that you have no way of knowing. Don't try to set the Content-Type header manually. XMLHttpRequest will generate it automatically from the FormData object.
You need a body parser for Express that supports multipart/form-data. The built-in one does not. The documentation for it on npm suggests 4 alternatives.
i am learning node js and i have a problem. basically I'm trying to create an api route that will make a call to an external api
but when I do a test with postman, I get the error "Cannot GET /api/books". has anyone have an idea?
here is my function. (for security reasons I did not add my APIkey in the post
const pool = require("../db");
const fetch = require('node-fetch');
exports.getOneBooksbyName = (req, res, next) => {
const title = req.params;
const APIKey = "";
fetch("https://www.googleapis.com/books/v1/volumes?q=" +title+ "&key="+APIKey)
.then(res => {
const data = res.json();
res.status(200).json(data);
}
)
.catch(err =>{
res.status(500).json({message:'error'})
})
};
and then my route
const express = require('express');
const router = express.Router();
const {getOneBooksbyName} = require('../controllers/books');
router.get('/?title', getOneBooksbyName);
module.exports = router;
and finally my app.js
const express = require("express");
const pool = require("./db.js")
const UserRoutes = require("./routes/user.js");
const app = express();
var bodyParser = require('body-parser');
const BookRoutes = require("./routes/book.js");
app.use(express.json()); //pour gerer les requetes POST
app.use(bodyParser.urlencoded({
extended: true
}));
app.use((req,res,next)=>{// POUR CONTOUNER LA SECURITE CORS
res.setHeader('Access-Control-Allow-Origin', '*');
res.setHeader('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content, Accept, Content-Type, Authorization');
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS');
next();
});
app.use('/api/users' , UserRoutes);
app.use('/api/books' , BookRoutes);
module.exports = app;
I use java script and jquery to achieve this
Javascript function using jquery ajax to call API via URL and return result
function api_fetch(url) {
var result = 0;
$.ajax({
url:url,
type: 'GET',
async: false,
dataType: 'html',
success: function (response) {
console.log(`response from fetch ${response}`)
result = response
},
error: function (error)
{
console.log(`response from fetch ${error}`)
result = error
}
})
return result
}
I personally created a Django API, and I need to check if there is a record for a number in a database, so I implemented another js function to call the API
function check_number(number) {
let get = api_fetch(`/api/verifnum/${number}`)
console.log(`check number fetch ${get}`)
}
when I console log check number it gives me desired result
check_number('number') // returns number of record if exist or 0
I have an http-proxy to proxy any website and inject some custom JS file before to serve the HTML back to the client. Whenever I try to access the proxied website, it will hang up or the browser seems to load indeterminately. But when I check the HTML source, I successfully managed to inject my custom JavaScript file. Here is the code:
const cheerio = require('cheerio');
const http = require('http');
const httpProxy = require('http-proxy');
const { ungzip } = require('node-gzip');
_initProxy(host: string) {
let proxy = httpProxy.createProxyServer({});
let option = {
target: host,
selfHandleResponse: true
};
proxy.on('proxyRes', function (proxyRes, req, res) {
let body = [];
proxyRes.on('data', function (chunk) {
body.push(chunk);
});
proxyRes.on('end', async function () {
let buffer = Buffer.concat(body);
if (proxyRes.headers['content-encoding'] === 'gzip') {
try {
let $ = null;
const decompressed = await ungzip(buffer);
const scriptTag = '<script src="my-customjs.js"></script>';
$ = await cheerio.load(decompressed.toString());
await $('body').append(scriptTag);
res.end($.html());
} catch (e) {
console.log(e);
}
}
});
});
let server = http.createServer(function (req, res) {
proxy.web(req, res, option, function (e) {
console.log(e);
});
});
console.log("listening on port 5051");
server.listen(5051);
}
Can someone please tell me if I am doing anything wrong, it looks like node-http-proxy is dying a lot and can't rely much on it since the proxy can work sometimes and die at the next run, depending on how many times I ran the server.
Your code looked fine so I was curious and tried it.
Although you do log a few errors, you don't handle several cases:
The server returns a body with no response (cheerio will generate an empty HTML body when this happens)
The server returns a response that is not gzipped (your code will silently discard the response)
I made a few modifications to your code.
Change initial options
let proxy = httpProxy.createProxyServer({
secure: false,
changeOrigin: true
});
Don't verify TLS certificates secure: false
Send the correct Host header changeOrigin: true
Remove the if statement and replace it with a ternary
const isCompressed = proxyRes.headers['content-encoding'] === 'gzip';
const decompressed = isCompressed ? await ungzip(buffer) : buffer;
You can also remove the 2 await on cheerio, Cheerio is not async and doesn't return an awaitable.
Final code
Here's the final code, which works. You mentioned that "it looks like node-http-proxy is dying a lot [...] depending on how many times I ran the server." I experienced no such stability issues, so your problems may lie elsewhere if that is happening (bad ram?)
const cheerio = require('cheerio');
const http = require('http');
const httpProxy = require('http-proxy');
const { ungzip } = require('node-gzip');
const host = 'https://github.com';
let proxy = httpProxy.createProxyServer({
secure: false,
changeOrigin: true
});
let option = {
target: host,
selfHandleResponse: true
};
proxy.on('proxyRes', function (proxyRes, req, res) {
console.log(`Proxy response with status code: ${proxyRes.statusCode} to url ${req.url}`);
if (proxyRes.statusCode == 301) {
throw new Error('You should probably do something here, I think there may be an httpProxy option to handle redirects');
}
let body = [];
proxyRes.on('data', function (chunk) {
body.push(chunk);
});
proxyRes.on('end', async function () {
let buffer = Buffer.concat(body);
try {
let $ = null;
const isCompressed = proxyRes.headers['content-encoding'] === 'gzip';
const decompressed = isCompressed ? await ungzip(buffer) : buffer;
const scriptTag = '<script src="my-customjs.js"></script>';
$ = cheerio.load(decompressed.toString());
$('body').append(scriptTag);
res.end($.html());
} catch (e) {
console.log(e);
}
});
});
let server = http.createServer(function (req, res) {
proxy.web(req, res, option, function (e) {
console.log(e);
});
});
console.log("listening on port 5051");
server.listen(5051);
I ended up writing a small Python Server using CherryPy and proxied the web app with mitmproxy. Everything is now working smoothly. Maybe I was doing it wrong with node-http-proxy but I also became sceptic about using it in a production environment.
I'm created a chat-bot using 'botact' library, but
when I'm trying to verificate my bot on vk-community API working page I receive an error in 'Windows PowerShell' (Here I started the server for bot):
TypeError: Cannot read property 'fwd_messages' of undefined
at Botact.getLastMessage (C:\Users\whoami\Desktop\Bot-test\node_modules\botact\lib\utils\getLastMessage.js:2:11)
at Botact.module.exports (C:\Users\whoami\Desktop\Bot-test\node_modules\botact\lib\methods\listen.js:29:28).
The file 'getLastMessage.js' contains this code:
const getLastMessage = (msg) => {
if (msg.fwd_messages && msg.fwd_messages.length) {
return getLastMessage(msg.fwd_messages[0])
}
return msg
}
module.exports = getLastMessage
So I don't know much about botact but according to the code when you are hitting the / route, you need to pass a body containing an object property.
Now as this is bot framework for vk bots maybe it automatically sends the request body. You can make sure by logging the request body.
server.post('/', async (req,res)=>{
console.dir(req.body);
await bot.listen(req, res);
});
/lib/methods/listen.js:
const { type, secret, object, group_id } = framework === 'koa'
? args[0].request.body
: args[0].body
...
...
...
const { events, middlewares } = actions
const forwarded = this.getLastMessage(object)
Now, when you do bot.listen express passes req as first argument. and { type, secret, object, group_id } these fields get distructured from the req.body.
And then object is getting passed to the getLastMessage function.
So for the request body in minimum you would need
{ "object": {} }
Here is the 200 OK output that I got after added that to the request body from Postman
POC Code:
const express = require("express");
const bodyParser = require("body-parser");
const { Botact } = require("botact");
const server = express();
const bot = new Botact({
token: "token_for_my_group_i_just_hided_it",
confirmation: "code_for_my_group_i_just_hided_it"
});
server.use(bodyParser.json());
server.post("/",bot.listen);
server.listen(8080);
I am troubling with nodejs proxy server modified(write) response.
I want to achieve auto login for one site via node proxy server and for that i have to query in database then i can modified response but it seems req ended before req.write and getting Error: write after end
Below is my implementation so far.
var express = require('express');
var proxy = require('http-proxy-middleware');
var options = {
target: 'http://example.com/', // target host
changeOrigin: true,
onProxyReq: function onProxyReq(proxyReq, req, res) {
var _write = res.write;
var body = "";
proxyReq.on('data', function(data) {
data = data.toString('utf-8');
body += data;
});
res.write = function (data) {
try{
//I have database query here instead of setTimeout
setTimeout(function(){
/* Modified response here and write */
_write.call(res, data); //can't write because req already end
},3000);
} catch (err) {
console.log('err',err);
}
}
}
}
// create the proxy (without context)
var exampleProxy = proxy(options);
// mount `exampleProxy` in web server
var app = express();
app.use('/', exampleProxy);
app.listen(8080);
Can anyone guide me how to achieve this ?