send post from webpage to Node.js server ...do not use 'fetch'...? - html

I am using the following javascript on a webpage to send information to a Node.js server upon a "click" on an image. This is using a 'POST' request.
<script>
function rerouter(_sent) {
var _people = <%- JSON.stringify(member_list) %>;
//convert the passed ('member_list') array into a JSON string...
var _attend = <%- JSON.stringify(online) %>;
//convert the passed ('online') array into a JSON string...
var splits = _sent.id.split("_"); //"split" on "underscore ('_')"
if (_people.indexOf(splits[1]) != -1) {
//**SEND INFO TO SERVER...
var available = _attend[_people.indexOf(splits[1])];
var response = fetch("members/pages/:" + splits[1] + "/presence/:" + available, {
method: 'POST',
headers: {
'Content-Type': 'text/plain;charset=utf-8'
}
});
//**
} //'_people' array contains the member name ('splits[1]')...
}
</script>
And here I handle the request in my Node.js server code:
var bodyParser = require('body-parser')
// create application/json parser
var jsonParser = bodyParser.json()
// create application/x-www-form-urlencoded parser
var urlencodedParser = bodyParser.urlencoded({ extended: false })
app.post('/members/pages/:membername/presence/:online', urlencodedParser, function (req, res) {
console.log("I RECEIVED FROM CLIENT THE FOLLOWING:")
console.log(req.params)
console.log(req.body)
res.redirect('/_landing');
})
Here is my console output:
I RECEIVED FROM CLIENT THE FOLLOWING:
{ membername: ':Nica', online: ':Yes' }
{}
As can be seen from my output, the POST route does seem to be functional, somewhat. However my 'redirect' command does NOT execute...the webpage does not change to the '_landing' page as it should...I think it may be because I am using 'fetch' to send the POST request...??? Can somebody verify if that is the cause (or another issue is the cause) and how I might be able to correct the issue?
In addition why does my 'params' include the colons (":") when I log to the console...is that standard? I would not think it would include the colons in the log, only the actual data.
Basically it seems my POST is almost working...but not exactly. Any suggestions would be greatly appreciated. I thank you in advance.
UPDATE: I have made some changes and my POST seems to be working fine now. In my frontend webpage I use the following to make the HTTP POST request:
<script>
function rerouter(_sent) {
var _people = <%- JSON.stringify(member_list) %>;
//convert the passed ('member_list') array into a JSON string...
var _attend = <%- JSON.stringify(online) %>;
//convert the passed ('online') array into a JSON string...
var splits = _sent.id.split("_"); //"split" on "underscore ('_')"
if (_people.indexOf(splits[1]) != -1) {
//**SEND INFO TO SERVER...
var available = _attend[_people.indexOf(splits[1])];
fetch('/members/pages/callup', {
method: 'post',
headers: {
'Accept': 'application/json, text/plain, */*',
'Content-Type': 'application/json'
},
body: JSON.stringify({name: splits[1], presence: available, str: 'Some string: &=&'})
})
//**
} //'_people' array contains the member name ('splits[1]')...
}
</script>
...And modified my route handler in my Node.js script:
// create application/json parser
var jsonParser = bodyParser.json()
app.post('/members/pages/callup', jsonParser, function (req, res) {
console.log("I RECEIVED FROM CLIENT THE FOLLOWING:")
console.log(req.body)
res.redirect('/_landing');
})
This is functional...to receive the data sent from the frontend webpage.
The only remaining problem is why does the 'redirect' not fire...??? I still have a feeling that by using a 'fetch' that somehow this is interfering with the page redirection...? A fetch would normally be used to wait for a response from the server, in my case I am not interested in that functionality I just want to send data one-way from frontend to backend...and then redirect the frontend page. I cannot think of any other reason why the redirect does not fire...?

Make extented:true instead of false as,
var urlencodedParser = bodyParser.urlencoded({ extended: true }) and move this line above of the below statement,
var jsonParser = bodyParser.json() and check if it works.
And finally change your headers here from,
headers: {
'Content-Type': 'text/plain;charset=utf-8'
}
To,
headers: {
'Content-Type': 'application/json'
}
Hope this will resolve the issue.

Related

Post array of objects with AngularJS $http

I am making an app where a user can submit multiple links to a form. The links are then stored in an array of objects before posting them to my backend. But somehow my JSON structure turns up like this in ExpressJS:
[
'{"title":"link1","url":"url1"}',
'{"title":"link2","url":"url2"}'
]
This is my angularJS:
$scope.saved_link = [];
$scope.uploadLink = function(title,url) {
$scope.saved_link.push({
title : title,
url : url
});
}
$scope.onSubmit = function(pubForm, url) {
var file = $scope.upload_file;
var fd = new FormData();
fd.append('file', file);
$http.post(url,fd, {
transformRequest: angular.identity,
headers: {'Content-Type': undefined},
params: {
links: $scope.saved_link,
image: file.name
}
}).then(function successCallBack(response){
})
}
Any one know how to get rid of those quotation marks?
I believe the Content-Type must be set for fixing the format.
Content-Type: application/json
Ref:
AngularJS $http
Alternatively,
you can try to parse the string into an object at the backend.
Ref:
JSON.parse()

CouchDb 2.1.1 Admin API Compaction PUT Request

I am working in NodeJS with CouchDB 2.1.1.
I'm using the http.request() method to set various config settings using the CouchDB API.
Here's their API reference, yes, I've read it:
Configuration API
Here's an example of a working request to set the logging level:
const http = require('http');
var configOptions = {
host: 'localhost',
path: '/_node/couchdb#localhost/_config/',
port:5984,
header: {
'Content-Type': 'application/json'
}
};
function setLogLevel(){
configOptions.path = configOptions.path+'log/level';
configOptions.method = 'PUT';
var responseString = '';
var req = http.request(configOptions, function(res){
res.on("data", function (data) {
responseString += data;
});
res.on("end", function () {
console.log("oldLogLevel: " + responseString);
});
});
var data = '\"critical\"';
req.write(data);
req.end();
}
setLogLevel();
I had to escape all the quotes and such, which was expected.
Now I'm trying to get CouchDb to accept a setting for compaction.
The problem is that I'm attempting to replicate this same request to a different setting but that setting doesn't have a simple structure, though it appears to be "just a String" as well.
The CouchDB API is yelling at me about invalid JSON formats and I've tried a boatload of escape sequences and attempts to parse the JSON in various ways to get it to behave the way I think it should.
I can use Chrome's Advanced Rest Client to send this payload, and it is successful:
Request Method: PUT
Request URL: http://localhost:5984/_node/couchdb#localhost/_config/compactions/_default
Request Body: "[{db_fragmentation, \"70%\"}, {view_fragmentation, \"60%\"}, {from, \"23:00\"}, {to, \"04:00\"}]"
This returns a "200 OK"
When I execute the following function in my node app, I get a response of:
{"error":"bad_request","reason":"invalid UTF-8 JSON"}
function setCompaction(){
configOptions.path = configOptions.path+'compactions/_default';
configOptions.method = 'PUT';
var responseString = '';
var req = http.request(configOptions, function(res){
res.on("data", function (data) {
responseString += data;
});
res.on("end", function () {
console.log("oldCompaction: " + responseString);
});
});
var data = "\"[{db_fragmentation, \"70%\"}, {view_fragmentation, \"60%\"}, {from, \"23:00\"}, {to, \"04:00\"}]\"";
req.write(data);
req.end();
}
Can someone point at what I'm missing here?
Thanks in advance.
You need to use node's JSON module to prepare the data for transport:
var data = '[{db_fragmentation, "70%"}, {view_fragmentation, "60%"}, {from, "23:00"}, {to, "04:00"}]';
// Show the formatted data for the requests' payload.
JSON.stringify(data);
> '"[{db_fragmentation, \\"70%\\"}, {view_fragmentation, \\"60%\\"}, {from, \\"23:
00\\"}, {to, \\"04:00\\"}]"'
// Format data for the payload.
req.write(JSON.stringify(data));

Sending nested object via post request

I'm running this little node express server, which is supposed to check if the voucher is valid later and then send an answer back to the client
this is my code
app.post('/voucher', function (request, response) {
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
if ( request.method === 'OPTIONS' ) {
response.writeHead(200);
response.end();
return;
}
console.log(request)
let results;
let body = [];
request.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
results = Buffer.concat(body).toString();
// results = JSON.parse(results);
console.log('#### CHECKING VOUCHER ####', results)
let success = {success: true, voucher: {name: results,
xxx: 10}}
success = qs.escape(JSON.stringify(success))
response.end(success)
} )
}
);
It is obviously just an example and the actual check is not implemented yet. So far so good.
Now on the client side where I work with REACT, I can not seem to decode the string I just send there.
there I'm doing this
var voucherchecker = $.post('http://localhost:8080/voucher', code , function(res) {
console.log(res)
let x = JSON.parse(res)
console.log(x)
console.log(qs.unescape(x))
It gives me the error
Uncaught SyntaxError: Unexpected token % in JSON at position 0
When I do it the other way arround
let x = qs.unescape(res)
console.log(x)
console.log(JSON.parse(x))
Than it tells me
Uncaught TypeError: _querystring2.default.unescape is not a function
Maybe you can help me? I don't know what the issue is here. Thank you.
Also another question on this behalf, since I'm only a beginner. Is there smarter ways to do such things than I'm doing it now? I have react which renders on the client and I have a mini express server which interacts a few times with it during the payment process.
The both run on different ports.
What would be the standard way or best practice to do such things?
I'm a bit perplexed as to why your backend code has so much going on in the request.
Since you asked for if there is a different way to write this, I will share with you how I would write it.
Server
It seems that you want your requests to enable CORS, it also seems that you originally wanted to parse a JSON in your request body.
This is how I would recommend you re-write your endpoint
POST /voucher to take a request with body JSON
{
code: "xxxxx"
}
and respond with
{
success: true,
voucher: {
name: results,
xxx: 10
}
}
I would recommend you use express's middleware feature as you will probably use CORS and parse JSON in most your requests so in your project I would.
npm install body-parser
npm install cors
then in your app initialization
var bodyParser = require('body-parser')
var cors = require('cors')
var app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json you can choose to just pars raw text as well
app.use(bodyParser.json())
// this will set Access-Control-Allow-Origin * similar for all response headers
app.use(cors())
You can read more about body-parser and cors in their respective repos, if you don't want to use them I would still recommend you use your own middleware in order to reduse future redundancy in your code.
So far this will substitute this part of your code
response.setHeader('Access-Control-Allow-Origin', '*');
response.setHeader('Access-Control-Request-Method', '*');
response.setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET');
response.setHeader('Access-Control-Allow-Headers', 'authorization, content-type');
if ( request.method === 'OPTIONS' ) {
response.writeHead(200);
response.end();
return;
}
console.log(request)
let results;
let body = [];
request.on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
results = Buffer.concat(body).toString();
// results = JSON.parse(results);
Now your route definition can just be
app.post('/voucher', function (request, response) {
var result = request.body.code // added by body-parser
console.log('#### CHECKING VOUCHER ####', result)
// express 4+ is smart enough to send this as json
response.status(200).send({
success: true,
voucher: {
name: results,
xxx: 10
}
})
})
Client
your client side can then be, assuming $ is jquery's post function
var body = {
code: code
}
$.post('http://localhost:8080/voucher', body).then(function(res) {
console.log(res)
console.log(res.data)
return res.data
})

Nodejs page freezes after multple requests to Custom API

The problem I have is that my application works when I submit only one 1 when I press the Submit button multiple times it freezes and after some time (about 1000.000 ms) it returns the last request in the console and jade page. The submit button returns a post from the form and sends it to the same page . What the button also does is Refreshing the page. It is important that the page returns the (JSON) post to the page and there is an other json request that sends it to the API(and returns it to the same page )
app.js
var options_search = {
hostname: 'host',
path: 'path',
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Content-Length': JSON request .length,
}
};
app.post('/result',function(req,response){
var keyword=req.body.user;
GLOBAL.objToJson ={ keyword };
response.write(JSON.stringify(GLOBAL.objToJson));
console.log("test " +JSON.stringify(GLOBAL.objToJson) );
});
app.get('/Search', function(req, res) {
var req = http.request(options_search, (resb) => {
var buffer_search = "";
resb.setEncoding('utf8');
resb.on('data', (chunks) => {
buffer_search += chunks;
});
resb.on('end', () => {
res.render('Search',{
title: 'Search',
value_search: buffer_search,
search_test: [JSON.stringify(GLOBAL.objToJson) ]
});
});
});
//res.redirect("/search");
req.write(search);
});
search.jade
doctype html
html
head
script(src='//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js')
script.
$(document).ready(function(){
var user,pass;
$("#submit").click(function(){
user=$("#user").val();
pass=$("#password").val();
$.post("http://localhost:3000/result",{user: user}, function(data){
if(data==='done')
{
alert("login success");
}
});
});
});
input#user(type='TEXT', size='40')
br
input#submit(type='button', value='Submit',onclick="location.href='search'")
In the result route you are using the underlying HTTP .write() method to respond to the client. However this does not end the connection, which will stay open expecting more things to be written to the client.
If you are sending a string you should use .send() as that will write the string to the HTTP stream and end the response.
You may also want to consider not stringifying the object to a JSON string and just using .json() instead. So the line of code
response.write(JSON.stringify(GLOBAL.objToJson));
becomes
response.json(GLOBAL.objToJson);

Node Express 4 get header in middleware missing

I have a middleware function using Node's Express4 to log each request & response for debugging. I use the res.json call in the request handler to send back JSON to the client for all but static files. So I do not want to log the response for static files, but only the JSON responses. I have the following code:
function logRequests(req, res, next) {
// do logging (will show user name before authentication)
logger.reqLog('IN '+req.method+' '+req.url, req);
var oldEnd = res.end,
oldWrite = res.write,
chunks = [];
res.write = function(chunk) {
chunks.push(chunk);
oldWrite.apply(res, arguments);
};
res.end = function(chunk, encoding) {
if(chunk) {
chunks.push(chunk);
}
oldEnd.apply(res, arguments);
// the content-type prints "undefined" in some cases
// even though the browser shows it returned as "application/json"
console.log('type='+res.get('content-type'));
if(res.get('content-type') === 'application/json') {
var body = Buffer.concat(chunks).toString('utf8');
logger.info(body, req);
}
logger.reqLog('OUT '+req.method+' '+req.path, req);
};
next(); // make sure we go to the next routes and don't stop here
}
So why do some requests show the correct content type in the middleware meaning they also print the response fine and others do not? All of them look good in the REST client when inspecting the returned headers.
EDIT: Some more info discovered tonight while trying to figure this out - if I append any character as a dummy request parameter, it logs the response type correctly:
http://localhost:8081/node/ionmed/api/logout?0 WORKS
where
http://localhost:8081/node/ionmed/api/logout DOES NOT
Also, I can always get a response type logging in the middleware function if I replace the .json() call with .end() so this:
res.json({ item: 'logout', success: true });
becomes:
res.set('content-type', 'application/json');
res.end({ item: 'logout', success: true });