Node.js (express) web server
Request handler in web server
app.get('/documents/ajax/:id.:format?', function(req, res) {
console.log ('Request Received');
var body = 'hello world';
res.writeHead(200, {
'Content-Length': body.length,
'Content-Type': 'text/plain'
});
})
ajax request from client side javascript
$.ajax({
url : "/documents/ajax/" + item,
success : function(msg) {
alert ("success" + msg);
},
error : function(request, status, error) {
alert("Error, returned: " + request);
alert("Error, returned: " + status);
alert("Error, returned: " + error);
}
});
I am able to receive the request on server side and I send 4 requests
But my success event is not getting called in client side JS. Also, when I stop my web server, then I see my error handlers get called.
Please help.
The main issue is that you are not ending the response so the server never actually sends anything to the client. The server should respond with something like a file, a redirect, some text, etc. You need to finish the callback with a res.end, res.send, res.sendfile, res.redirect, res.render... See the docs.
Furthermore, with express you want to use res.set to set the http headers:
app.get('/documents/ajax/:id.:format?', function(req, res) {
console.log ('Request Received');
var body = 'hello world';
res.set({'Content-Type': 'text/plain'});
res.send(body);
});
200 is the default response code, so you don't need to specify that and the length will be computed for you. These things are often easier to debug from the command line via curl:
curl http://localhost:3000/documents/ajax/1
and
curl -I http://localhost:3000/documents/ajax/1
I had to res.end in server request handler. After that I was able to generate success event in client side JS
Related
Here's the code:
proxy.web(
req,
res,
{ changeOrigin: false, target: 'http://' + gotDomain.ip + ':' + gotDomain.port },
function (error, req, res) => {
console.log('Error')
res.end('Error')
}
)
If I stop the target server, the console log fires.
The response res.end('Error') does not work.
The request just hangs on the client side. I can run any code I want in the error callback and I can see the res variable is an http response object. I've tried adding:
res.writeHead(500, {
'Content-Type': 'text/plain'
});
I've tried using the proxy.on('error'... setup and the results are exactly the same:
The callback runs
The res variable is a valid http response object
Whatever I put in res.end() doesn't get sent to the client
The client hangs forever waiting for a response.
I've checked this answer:
Node.js http-proxy: Error response not sent to client
I'm not sure how that solution could work because my proxy response doesn't have status() or send() methods. I get TypeError: res.status is not a function if I try those.
With http-proxy, I use end() whenever I'm returning a response.
Running an express server with route handler like this:
app.get('*', (req, res) => {
console.log('Received request');
setTimeout(() => {
res.end();
console.log('Ended request');
}, 3000);
});
If one visits the route '/foo' and then immediately '/bar' (in two different tabs), this will be output via console.log:
Received request
Received request
Ended request
Ended request
But if you do the same except visiting '/foo' in both tabs, the server waits for the first request before handling the second:
Received request
Ended request
Received request
Ended request
I believed all method requests were handled asynchronously, but this seems to be an exception. Could anyone provide an in-depth explanation on why this happens? I have not been able to find any info in the express documentation.
Testing using Windows 10 Node.js v8.1.3 and Chrome as well as MS Edge browsers showed something interesting. Using your original posted code and making the http request using Chrome gave the same delayed second response behavior that you described. Modifying the code to include writing responses to the request client like:
app.get('*', (req, res) => {
console.log('Received request');
res.write("Request received\n");
setTimeout(() => {
res.write("Ending request response");
res.end();
console.log('Ended request');
}, 3000);
});
gave the expected result.
Neither the first nor second http response was delayed by the first code version when made with MS Edge. Based on that, it looks like the comment from Brahma Dev about the browser cache optimization is correct.
Below is the results I have got and which is expected as of Async(Node Way)
To Make it Simple I have modified code as
app.get('*', (req, res) => {
var requestURL = req.url;
console.log('Received request : ' + requestURL + ' on Time : ' + new Date().toISOString());
setTimeout(() => {
res.end();
console.log('Ended request : ' + requestURL + ' on Time : ' + new Date().toISOString());
}, 15000);
});
I have fired the 4 URLS with different tabs and in Firefox at same time with URLS as
http://localhost:3000/footab1
http://localhost:3000/bar
http://localhost:3000/bar
http://localhost:3000/booztab1
Here the difference what we can see that NodeJs is firing all the URL which are unique are fired instantaneously without waiting for the 1st Request to get complete hence its behaving as proper and in my above test since I have used /bar two times browser called only once because you are hitting the Same endpoint in two tabs
If you were using other Sync Programming languages such as PHP,JAVA you would expect result as Received request>Ended request then your 2nd Request would have processed
Received request : /bar on Time : 2018-02-18T18:17:50.250Z
Received request : /booztab1 on Time : 2018-02-18T18:17:50.253Z
Received request : /footab1 on Time : 2018-02-18T18:17:50.253Z
Ended request : /bar on Time : 2018-02-18T18:18:05.268Z
Ended request : /booztab1 on Time : 2018-02-18T18:18:05.268Z
Ended request : /footab1 on Time : 2018-02-18T18:18:05.268Z
Received request : /bar on Time : 2018-02-18T18:18:05.268Z
Ended request : /bar on Time : 2018-02-18T18:18:20.290Z
My express app should call a function once, but it repeatedly calls it an infinite number of times when handling a POST request. I can't figure out why it's called more than once.
This app works with Slack Events API and receives an event from Slack as a post request when a message is posted to a specific Slack channel. Once the app receives the event, it responds with a 200-status response to alert Slack it received it. Then the app extracts the text property from the request and calls postMessage with the text to post the message to a different channel. Posting the message to a different channel won't kick off another event.
The problem is that postMessage() gets called infinitely until I manually crash the app
Here I setup the app and wait for post requests:
const express = require('express');
var bodyParser = require('body-parser');
var app = express();
var jsonParser = bodyParser.json();
// Wait for post requests, then extract it's text
app.post('/', jsonParser, function (req, res) {
if (!req.body){
return res.sendStatus(400);
} else {
postMessage(req.body.event.text); //Should be called once
}
// Respond to Slack Event API we received their request
res.writeHead(200, {'Content-Type': 'application/json'});
res.end();
});
}
app.listen(config('PORT'), (err) => {
if (err) throw err
console.log(`App LIVES on PORT ${config('PORT')}`);
});
The body of the request is structured like:
body = {
event: {
text: "important message"
}
}
The function that keeps getting called. This will post a message to a Slack channel:
function postMessage(message){
var messagePath = 'https://slack.com/api/chat.postMessage?token=xxx&message=' + message;
request(messagePath, function(error, response, body){
if (!error && response.statusCode == 200){
console.log('message sent successfully');
} else {
console.log('error == ' + error);
}
});
}
The postMessage method does get called with the correct text. The problem is that it's called more than once.
I thought Slack's API was possibly sending the same request multiple times but from their documentation they will wait 3 seconds between sending requests. My app will call postMessage() about a hundred times in a second, so I don't think it's being overloaded with requests from Slack
Thank you in advance!
My guess is that your bot, which is listening to posted messages and then responding to those messages, is responding to itself when it posts. This will lead to an infinite loop.
The fix is to write a check to make sure the bot is not responding to itself. Inspect req.body.event and see if a username is being sent with each message. Then you can write something like this:
app.post('/', jsonParser, function (req, res) {
if (!req.body || !req.body.event){
return res.sendStatus(400);
} else if (req.body.event.user_name !== '<OUR_USER_NAME>') { // Make sure we are not responding to ourselves
postMessage(req.body.event.text); // Should be called once
}
// Respond to Slack Event API we received their request
res.writeHead(200, {'Content-Type': 'application/json'});
res.end();
});
I did not know what to write as the title, as I am having a very strange issue. What I am trying to do is upload and save *.html files on server. Following is the code structure:
Jade Template (Form):
#template-uploader
form(enctype='multipart/form-data')
input(name='file', type='file')
input#upload-template(type='button', value='Upload')
JS (Form Handle):
//Upload Btn Click Event Handler
$('#upload-template').on('click', function(){
event.stopPropagation();
event.preventDefault();
uploadFiles();
});
// Upload the files using AJAX
function uploadFiles()
{
var formData = $('input[type=file]')[0].files;
$.ajax({
url: 'template/upload',
type: 'POST',
xhr: function() { // Custom XMLHttpRequest
var myXhr = $.ajaxSettings.xhr();
if(myXhr.upload){
// For handling the progress of the upload
}
return myXhr;
},
data: formData[0],
cache: false,
processData: false, // Don't process the files
contentType: false, // Set content type to false as jQuery will tell the server its a query string request
success: function(data, textStatus, jqXHR)
{
console.log('Data');
console.log(data);
if(typeof data.error === 'undefined')
{
// Success so call function to process the form
}
else
{
// Handle errors here
console.log('ERRORS: ' + data.error);
}
},
error: function(jqXHR, textStatus, errorThrown)
{
// Handle errors here
console.log('ERRORS: ' + errorThrown);
// STOP LOADING SPINNER
}
});
}
Server (Node.js)
//Route handler for template file uploaded
router.post('/template/upload', function(req, res) {
console.log('Uploading Files');
console.log(req.files);
});
Now the issue is that when I select a file and click the upload button, an ajax request is made. I have logged the data that I am sending and seems good at the client end. On server side there are however two issues.
(Issue solved by answer from #Scimonster)I don't see any file in req.files param. I did this before in Express 3.x without any issues. Now I am using Express 4.x, and maybe I am missing something.
The second issue is that when the request is sent to server, the terminal immediately logs the console.log('Uploading Files') message. But I don't receive any error or success message on client side. I also don't see in terminal that a POST request was received for the mentioned route. However after 2 minutes (every time), the terminal logs the request received for the route including the console.log() message. And this is when I get a response on client side.
Terminal Logging:
Uploading Files
undefined
POST /dashboard/template/upload 200 **120004ms**
Uploading Files
undefined
This is beyond me. I don't think there are any pre-flight checks generated by client side.If someone can provide insight as to what might the issue be, that'd be great.
req.files from Express 3 is from the body parser middleware. In 4.x, this is no longer packaged with Express. You can install multer and include it as explained in the docs to enable req.files.
I am using AngularJs with NodeJs.
I have a scenario when upon a successful HTTP POST request, I need to redirect the user.
In the client through AngularJS, I make a HTTP POST request to a route:
$http.post('/aPath', data)
.success(function (result) {
//Handle success
})
.error(function (err) {
//Handle error
});
This route is handled within NodeJs that then does the actual POST. Upon success, within the route handler, I redirect:
function handlePostRequest (req, res) {
//Route handler
//HTTP POST Request
//Following code called when POST request is successful
if (result) {
//Successful post
res.redirect("http://www.google.com");
}
}
However, the browser does not navigate to google. Instead, in the error handler of the POST request within the AngularJS client, the control is reached.
I checked the server and find that the POST request is returned as status code 302 and thus is picked by the error handler for the POST request in the client.
I cannot figure out why, when the server successfully executes the redirect code, the control still reaches the client and that too the error handler. How do I redirect successfully?
Is it a HTTP POST in angular or an XHR? If it's an XHR you can't redirect the client from serverside, you'd need to send back an error which you then handle in your clientside script such as:
$http({
method: 'POST',
url: 'yoururl',
}).success(function(data, status, headers, config) {
// success stuff
}).error(function(data, status, headers, config) {
if (status == 302) {
window.location = headers('Location');
}
})
Successful XHRs come back with a status of 200. Your server handing back a 302 is technically correct, but it isn't what $http in Angular is expecting. If your server can hand you a 200, you can then do your redirect in the .success function of the $http request.