I'm new to Node.js.
I'm creating a simple node/express application that serves a single web page containing one button that when clicked makes a jQuery ajax request to an Express route.
The route callback makes an http.get request to openexchangerates.org for some json data containing foreign exchange rates. The JSON is then output to the Developer Tools console window.
The application works on the first button click, but on any subsequent clicks the console window displays:
GET http://127.0.0.1:3000/getFx net::ERR_CONNECTION_REFUSED
A screen grab of the Developer Tools console window shows the result of the first click, and then the second click when the connection is refused.
The error detail is as follows:
GET http://127.0.0.1:3000/getFx net::ERR_CONNECTION_REFUSED jquery-2.1.3.min.js:4
n.ajaxTransport.k.cors.a.crossDomain.send jquery-2.1.3.min.js:4
n.extend.ajax (index):18
(anonymous function) jquery-2.1.3.min.js:3
n.event.dispatch jquery-2.1.3.min.js:3
n.event.add.r.handle
My simple Node/Express application is as follows:
var express = require('express');
var app = express();
var http = require("http");
var data = "";
var json;
console.log( "__dirname", __dirname );
app.use( express.static( __dirname + '/') );
var options = {
host:"openexchangerates.org",
path:"/api/latest.json?app_id=<get free ID from openexchangerates.org>"
};
app.get("/", function( req, res ) {
res.sendFile('index.html', { root: __dirname });
})
app.get("/getfx", function(req, res) {
console.log("Route: getFx");
getFx(res);
})
function getFx(res) {
console.log("http getFx");
http.get(options, function (response) {
response.on("data", function (chunk) {
//console.log("data:\n"+chunk);
data += chunk;
});
response.on("end", function () {
json = JSON.parse(data);
console.log("http response end:");
res.end( data );
});
response.on("error", function (e) {
console.log("error:\n" + e.message);
});
})
}
app.listen(3000);
My html index page is:
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8">
<title>Get FX</title>
<script src="http://code.jquery.com/jquery-2.1.3.min.js"></script>
<script>
$(document).ready(function() {
console.log( "document ready");
$("#btnFx").click(function() {
console.log('clicked', this );
$.ajax({
url : "http://127.0.0.1:3000/getFx",
dataType : "json",
success : function(json) {
console.log("json returned:\n", json);
}
});
} );
})
</script>
</head>
<body>
<button id="btnFx" style="width:200px">Get foreign exchange rates</button>
</body>
For openexchangerates.org to serve the data, a free app id is required. Anyone able to help resolve this may have to go through their very short sign up:
That link is here:
https://openexchangerates.org/signup/free
However it's possible that my mistake is glowingly obvious to those with better Node/Express/jQuery knowledge.
Many thanks in advance
The way you defined your data and json vars is causing subsequent requests to fail. Since you defined them up front, all requests will re-use them, meaning by the time you JSON.parse data for the second request, data will contain two valid json strings, thus making one invalid json string. To fix this, define data and json farther down in the callback.
var express = require('express');
var app = express();
var http = require("http");
//var data = "";
//var json;
console.log( "__dirname", __dirname );
app.use( express.static( __dirname + '/') );
var options = {
host:"openexchangerates.org",
path:"/api/latest.json?app_id=<get free ID from openexchangerates.org>"
};
app.get("/", function( req, res ) {
res.sendFile('index.html', { root: __dirname });
})
app.get("/getfx", function(req, res) {
console.log("Route: getFx");
getFx(res);
})
function getFx(res) {
console.log("http getFx");
http.get(options, function (response) {
var data = "";
var json;
response.on("data", function (chunk) {
//console.log("data:\n"+chunk);
data += chunk;
});
response.on("end", function () {
console.log("http response end:");
json = JSON.parse(data);
res.json(json);
});
response.on("error", function (e) {
console.log("error:\n" + e.message);
});
})
}
app.listen(3000);
Issue comes from Cross origin requests protection which happens on localhost with chrome. Try to use other browser or just Allow origin to all hosts (*) or your host (http://localhost:3000):
app.use( express.static( __dirname + '/') );
app.use(function(req,res,next){
res.header('Access-Control-Allow-Origin', '*');
res.header('Access-Control-Allow-Methods', 'GET,PUT,POST,DELETE,OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization, Content-Length, X-Requested-With');
// intercept OPTIONS method
if ('OPTIONS' == req.method) {
res.send(200);
}
else {
next();
}
});
Related
I'm trying to send a post parameter (key: test, value: somevlaue) using PostMan using restify framework. For this I've used 2 methods and both are not working:
1st one shows this error:
{
"code": "InternalError",
"message": "Cannot read property 'test' of undefined"
}
2nd one (commented) shows only Error: someerror
Am I doing something wrong?
Here's my code:
var restify=require('restify');
var fs=require('fs');
var qs = require('querystring');
var bodyParser = require('body-parser');
var urlencodedParser = bodyParser.urlencoded({ extended: false })
var controllers = {};
var server=restify.createServer();
server.post("/get", function(req, res, next){
res.send({value: req.body.test,
error: "someerror"});
//**********METHOD TWO*********************
/*
if (req.method == 'POST') {
var body = '';
req.on('data', function (data) {
body += data;
});
req.on('end', function () {
var post = qs.parse(body);
res.send({
Data: post.test,
Error: "Someerror"
});
});
}
*/
});
server.listen(8081, function (err) {
if (err)
console.error(err);
else
console.log('App is ready at : ' + 8081);
});
With restify ^7.7.0, you don't have to require('body-parser') any more. Just use restify.plugins.bodyParser():
var server = restify.createServer()
server.listen(port, () => console.log(`${server.name} listening ${server.url}`))
server.use(restify.plugins.bodyParser()) // can parse Content-type: 'application/x-www-form-urlencoded'
server.post('/your_url', your_handler_func)
It looks like you might have your bodyparser set up incorrectly.
According to the docs under the body parser section you set up the parser in this manner:
server.use(restify.bodyParser({
maxBodySize: 0,
mapParams: true,
mapFiles: false,
.....
}));
The default is to map the data to req.params but you can change this and map it to req.body by setting the mapParams option to false
BodyParser
Blocks your chain on reading and parsing the HTTP request body.
Switches on Content-Type and does the appropriate logic.
application/json, application/x-www-form-urlencoded and
multipart/form-data are currently supported.
Inside my application code, for a specific set of APIs, I'm making a NodeJS request like following, which should return a image as the body. This same request works fine on Postman (and I can see the image).
module.exports = {
getThumbnail: function (thumbnailUrn, env, token, onsuccess){
request({
url: config.baseURL(env) + config.thumbail(thumbnailUrn),
method: "GET",
headers: {
'Authorization': 'Bearer ' + token,
}
}, function (error, response, body) {
// error check removed for simplicity...
onsuccess(body);
});
}
}
The above code run under my own security checks and adds the token header. It works fine (request calls return 200/OK).
Now on my app router I want to respond this as an image, but the output is not being interpreted as an image. Here is what I have:
var dm = require(/*the above code*/);
// express router
var express = require('express');
var router = express.Router();
router.get('/getThumbnail', function (req, res) {
var urn = req.query.urn;
dm.getThumbnail(urn, req.session.env, req.session.oauthcode, function (thumb) {
res.writeHead(200,
{
'Content-Type': 'image/png'
}
);
// at this point, the 'thumb' variable is filled
// but I believe is not properly encoded...
// or maybe the res.end output is missing something...
res.end(thumb, 'binary');
});
});
module.exports = router;
EDIT: as commented by Nodari Lipartiya, this is kind of proxy behaviour ( server(responds with image) -> proxy (node.js/resends to client) -> end user)
I'm not sure what is coming back in thumb, but the following snippet seemed to work for me (bypassing Express for simplicity):
var http = require("http")
var fs = require("fs")
var server = http.createServer(listener)
server.listen(() => {
console.log(server.address().port)
})
var binary = fs.readFileSync("path to local image")
function listener(req, resp) {
resp.writeHead(200,
{
'Content-Type': 'image/png'
}
);
resp.end(new Buffer(binary), "binary")
}
What happens if you wrap it in a Buffer?
If I've understood everything correctly:
I did this
server.js
var fs = require('fs');
var express = require('express');
var app = express();
app.get('/img', function(req, res, next) {
var stream = fs.createReadStream('img.jpeg');
var filename = "img.jpeg";
filename = encodeURIComponent(filename);
res.setHeader('Content-disposition', 'inline; filename="' + filename + '"');
res.setHeader('Content-type', 'image/jpeg');
stream.pipe(res);
});
app.listen(9999, function () {
console.log('Example app listening on port 9999!');
});
proxy.js
var request = require('request');
var express = require('express');
var app = express();
app.get('/img', function(req, res, next) {
console.log('proxy/img');
request({
url: 'http://localhost:9999/img',
method: "GET",
}, function (error, response, body) {
res.end(body, 'binary');
});
});
app.listen(9998, function () {
console.log('Example app listening on port 9998!');
});
req.js
var request = require('request');
request({
url: 'http://localhost:9998/img',
method: "GET",
}, function (error, response, body) {
console.log('body', body);
});
works for me. Please, let me know if you'll need help.
I have a REST API server which is running on one VM1. On other VM2 machine I have built a node js server which is running as proxy. On the same VM2 machine I have application (hosted with apache which serves only html, js and css files). My node js server only resends the api calls back to the API server. This is working fine, until new requirement arrive - to add a new API endpoint (on the node js server) to download files (csv). In order to make download happen, I need to use GET method. The thing is that the required data is available only on POST endpoint from the main API server, and I am calling the API endpoint to get the data and send it back. This is the code I am trying to work it out:
var express = require('express');
var cors = require('cors');
var request = require('request');
var http = require('http');
var csv = require("fast-csv");
var config = require("./config.js");
var corsOptions = {
origin: function(origin, callback){
var originIsWhitelisted = config.whitelist.indexOf(origin) !== -1;
callback(null, originIsWhitelisted);
}
};
var handler = function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
};
var app = express();
// Enable CORS for all requests
app.use(cors(corsOptions));
app.options('*', cors(corsOptions)); // specially for pre-flight requests
app.get('/download', function(req, res){
var limit = req.query.limit;
var offset = req.query.offset;
var options = {
method: 'POST',
url: config.apiServerHost + '/search',
useQuerystring: true,
qs: {'limit': limit, 'offset': offset},
rejectUnauthorized: false,
body: 'from=date&to=date'
};
var filename = 'data.csv';
res.setHeader('Content-disposition', 'attachment; filename=\"data.csv\"');
res.setHeader('content-type', 'text/csv');
var csvStream = csv.createWriteStream({
headers: true,
objectMode: true,
transform: function (row) {
return row;
}
});
console.log(options);
function callback(error, response, body) {
if (!error && response.statusCode == 200) {
var data = JSON.parse(body);
for(var i = 0; i < data.length; i++)
csvStream.write({
"col1": "value1-"+data[0][i],
"col2": "value2-"+data[1][i],
"col3": "value3-"+data[2][i],
"col4": "value4-"+data[3][i]
});
}
csvStream.end();
}
else {
console.log("Error:", error, body);
}
}
req.pipe(request(options, callback));//.pipe(res)
csvStream.pipe(res);
});
app.use('/api', function(req, res) {
var url = config.apiServerHost + req.url;
console.log(url);
req.pipe(request({
"rejectUnauthorized": false,
"url": url
}, function(error, response, body){
if(error) {
console.log(new Date().toLocaleString(), error);
}
})).pipe(res);
});
This all code works fine when request method is POST (the same as main API server). However I receive "[Error: write after end]" when I add the body in options object. Can someone help me figure out what is happening and how to solve this problem? Thanks.
The [Error: write after end] show pip data after .end(), for your codes
req.pipe(request(options, callback));//.pipe(res)
csvStream.pipe(res);
In the callback function, the csvStream.end(); is called, then invoke csvStream.pipe could cause this error.
Below is my express server. I am trying to make a get request in ajax, but it turned out failed even though I required jquery at the beginning. It said $ is not defined Other than using jquery ajax, what else can I use to make an API call form RESTful API url?
var express = require('express');
var requestHandler = require('./requestHandler');
var app = express();
var path = require('path');
app.use(express.static(path.join(__dirname, '../client')));
app.get('/homepage', requestHandler.getData);
var port = process.env.PORT || 3000;
app.listen(port);
console.log("Server running at: http://localhost:" + port);
// request handler file:
var express = require('express');
var url = "http://jsonplaceholder.typicode.com/";
module.exports.getData = function (req, res){
$.ajax({
method: 'GET',
url: url+'posts',
success: function(data) {
console.log(data);
res.send(data);
}
});
}
module.exports.getComments = function(userId){
$.ajax({
method: 'GET',
url: url+'/comments',
success: function(data) {
console.log(data);
}
});
}
HTTP GET Request in Node.js Express
var http = require('http');
var options = {
host: 'www.google.com',
path: '/index.html'
};
var req = http.get(options, function(res) {
console.log('STATUS: ' + res.statusCode);
console.log('HEADERS: ' + JSON.stringify(res.headers));
// Buffer the body entirely for processing as a whole.
var bodyChunks = [];
res.on('data', function(chunk) {
// You can process streamed parts here...
bodyChunks.push(chunk);
}).on('end', function() {
var body = Buffer.concat(bodyChunks);
console.log('BODY: ' + body);
// ...and/or process the entire body here.
})
});
req.on('error', function(e) {
console.log('ERROR: ' + e.message);
});
You need to understand things like:
expressjs is serverside code so it can't use jquery ajax like that.
jQuery.ajax() can only be used at view when you load your page in the browser.
You need to use some view engines like jade to create templates and use routers to push the view in the browser. When you have your view in the browser then you can make a reference to the script file which can contain your ajax code to let you have posts and comments.
More information.
Try something like this:
function() {
// Simple POST request example (passing data) :
$http.post("/createProject/"+ id +"", {
projectTitle: pTitle,
userID : id
}).
success(function(data, status, headers, config) {
// this callback will be called asynchronously
// when the response is available
$scope.getProjects();
console.log("project created");
console.log("this is the response data " + data);
}).
error(function(data, status, headers, config) {
// called asynchronously if an error occurs
// or server returns response with an error status.
});
};
Also please note. you will call this from an external JavaScript file. One the express server you will only have "routes" and from external javascript files you can perform HTTP calls on those routes.
Update
#Someone, the express framework is very popular to setup a web server in Node. You can use different render engines to render the view and pass information to the user. This is a very simple example from the Express website listening to two urls (/posts and /comments).
var express = require('express');
var app = express();
app.get('/posts', function (req, res) {
res.send('Render posts!');
});
app.get('/comments', function (req, res) {
res.send('Render comments');
});
var server = app.listen(3000, function () {
var host = server.address().address;
var port = server.address().port;
console.log('Example app listening at http://%s:%s', host, port);
});
I would like to develop a client server side with nodejs and javascript/jquery but I am stuck.
I have a big form, user submits and data are send to /getData url and that works perfectly. But my problem now it's when I want to get those data from /getData to my client side.
This is my client file:
var client = {};
client.start = function () {
client.getData();
};
client.cb_get = function () {
var data={};
if (this.readyState == 4 && this.status == 200) {
data= JSON.parse(this.responseText);
alert("We get the data" + JSON.stringify(data, null, 4));
client.chart(data);
} else {
alert("Sorry this page is not allow without processing any form");
}
};
client.get = function(req, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", req, true);
xhr.onreadystatechange = cb;
xhr.send();
};
client.getData= function () {
var req="http://localhost:3000/getData";
client.get(req,client.cb_get);
};
client.chart= function (data) {
//Display data as charts using jquery in an other html page.
};
window.onload = setTimeout(client.start, 1);
HTMLElement.prototype.has_class = function (c)
{
return this.className.indexOf(c) >= 0;
};
But I have a 404 error all the time and I don't know why.
my server file :
var express = require('express')
bodyParser =require("body-parser");
routes= require('./router.js');
var app= express();
app.use(express.static(__dirname + '/'));
//Here we are configuring express to use body-parser as middle-ware.
app.use(bodyParser.urlencoded({ extended: false }));
//define our routes
app.get('/', routes.index); //open home page
app.get('/simulation', routes.simulation);
app.get('/chartData', routes.chartData);
app.post('/getData', routes.getData);
//In case of malicious attacks or mistyped URLs
app.all('*', function(req, res){
res.send(404);
})
var server = app.listen(3000, function () {
var host = server.address().address
var port = server.address().port
console.log('Example app listening at http://%s:%s', host, port)
})
my router file:
module.exports.index= function(req, res){
fs.readFile('index.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
};
module.exports.simulation= function(req, res){
fs.readFile('simulation.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
};
module.exports.chartData= function(req,res) {
fs.readFile('chartPage.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
};
module.exports.getData= function(req,res) {
var data= {};
data= req.body;
res.send(JSON.stringify(data, null, 4));
console.log(req.body);
};
So where I am wrong?
Moreover, when I submit, my /getdata page opens (normal due to action= /getData specified in my form tag) but I want to open directly my html page with charts. How can I do that?
Sorry guys for my long post, but I really need help.
Your ajax request does
xhr.open("GET", "http://localhost:3000/getData", true);
your route listens for
app.post('/getData', routes.getData);
notice how you send a GET request and listen for a POST request, it's not the same thing, so you end up in the 404 route instead.
You either have to change the ajax request, and send a POST request, or the route and listen for a GET request.