NodeJS response.render():Can't set headers after they are sent - javascript

So, the first render is successful app.get("/", function(request, response), but when I process app.post("/search", urlencodedParser, function(request, response)
I get the Error:
c:\weather\views\main.hbs: Can't set headers after they are sent.
I read that, The functionres.render()should only be called once per request., but I don't understand - How Can I change datas using views(Handlebars), if i can't call render again with new datas?
var express = require("express");
var fs = require("fs");
var bodyParser = require("body-parser");
var hbs = require("hbs");
// create object
var app = express();
//urlEncoded
var urlencodedParser = bodyParser.urlencoded({
extended: false
});
//read city.json
var content = fs.readFileSync("./city.list.json", "utf8");
var cities = JSON.parse(content);
//set view Handlebars
app.set("view engine", "hbs");
//register Helper - ResultBlock
hbs.registerHelper("ResultBlock", function(array) {
var res = "";
if (array[0] == "false") {
res = '<div class="alert alert-warning alert-dismissible fade show"><button type="button" class="close" data-dismiss="alert">×</button><strong>Not Found!</strong> The ' + array[1] + ' is not correct.</div>';
} else if (array[0] == "true") {
res = 'Succsesful!!!';
}
return new hbs.SafeString(res);
})
app.get("/", function(request, response) {
//response.sendfile('index.html');
response.render("main.hbs", {
city_value: "Zaporozhye",
data: []
})
});
app.post("/search", urlencodedParser, function(request, response) {
var city = request.body.city;
var idCity = -1;
for (let i = 0; i < cities.length; i++) {
if (cities[i].name == city) {
idCity = cities[i].id;
break;
}
}
if (idCity != -1) {
response.render("main.hbs", {
city_value: city,
data: ["true", city]
})
} else {
response.render("main.hbs", {
city_value: city,
data: ["false", city]
})
}
response.end();
});
app.listen(3000);
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<script src="app.js" type=""></script>
<link rel="stylesheet" href="style.css">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Popper JS -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container-fluid" style="background-color:black; color:darkorange;">
<div class="row">
<div class="col">
<h1>Weather</h1>
</div>
<div class="col-*-*">
<form action="/search" method="post">
<div class="row">
<div class="col">
<input type="text" class="form-control" name="city" value="{{city_value}}" />
</div>
<div class="col">
<button type="submit" class="btn btn-primary">Search</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div id="result_block" class="container">
{{ResultBlock data}}
</div>
</body>
</html>

response.render is an asynchronous function. So the rendering is done after the current execution context finish.
At the end of your code your call response.end() and because of that you finish the response before the rendering has started.
After you finished the response the asynchronous rendering function will start and tries to set the headers, but this is not possible because the response is already finished, and that's the reason why you get that error.
Remove the response.end() and everything should work fine.

You should delete response.end() line, since you used response.render

The function response.end() is used the send the headers of the response and ends the response process.
On the other hand, the function response.render() renders the view, and also sends the headers and ends the response.
Calling both on the same response object will try to send headers twice for the same Request, which is not possible as each request can have only one response.
So, removing the response.end() from the end of post route handler for '/search' should solve the problem.
Updated Code for '/search' POST route handler:
app.post("/search", urlencodedParser, function(request, response) {
var city = request.body.city;
var idCity = -1;
for (let i = 0; i < cities.length; i++) {
if (cities[i].name == city) {
idCity = cities[i].id;
break;
}
}
if (idCity != -1) {
response.render("main.hbs", {
city_value: city,
data: ["true", city]
})
} else {
response.render("main.hbs", {
city_value: city,
data: ["false", city]
})
}
});

Related

Problem of NodeJS & JavaScript: webpage no output [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 11 months ago.
newsfeed.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>News Feed</title>
<link rel = "stylesheet" href = "stylesheets/style.css">
<script src = "javascripts/script.js"></script>
</head>
<body onload = "showNewsFeed()">
<!-- (i) -->
<div id = "header">
<input id="searchNewsHeadline" type="text">
<button onclick="">Search news headlines</button>
<a>Login</a>
</div>
<!-- (ii) -->
<div id = "news">
<!-- Display news entries -->
</div>
<!-- (iii) -->
<div id = "pageindex">
<!-- page indices -->
</div>
</body>
</html>
app.js
var express = require('express');
var app = express();
var monk = require('monk');
var db = monk('127.0.0.1:27017/assignment1');
// Make db accessible to router
app.use(function(req,res,next){
req.db = db;
next();
});
var server = app.listen(8081, function () {
var host = server.address().address;
var port = server.address().port;
console.log("Example app listening at http://%s:%s", host, port);
})
app.get('/newsfeed.html', function(req, res){
var db = req.db;
var newsList = db.get('newsList');
var response = "";
newsList.find({}, ['-_id', 'headline', 'date', 'content', '-comments']).each((news) =>{
response += "<h4>" + news['headline'] + "</h4>";
response += "<h6>" + news['date'] + "</h6>";
response += "<p>" + news['content'] + "</p>";
})
res.send(response);
});
script.js
function showNewsFeed(){
var xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function(){
if (xmlhttp.readyState == 4 && xmlhttp.status == 200){
var newsfeeds = JSON.parse(xmlhttp.responseText);
document.getElementById("news").innerHTML = newsfeeds;
}
}
xmlhttp.open("GET", "/newsfeed.html", true);
xmlhttp.send();
}
I am working on an assignment that fetches newsfeeds from a MongoDB database and then puts them onto the webpage (newsfeed.html). I tried to do so with these codes, it return a blank page with no output. I do believe the database is linked correctly and I am not sure which part goes wrong as no error message is kicking back.
app.get('/newsfeed.html', function(req, res){
var db = req.db;
var newsList = db.get('newsList');
var response = "";
newsList.find({}, ['-_id', 'headline', 'date', 'content', '-comments']).each((news) =>{
response += "<li><h4>" + news['headline'] + "</h4>";
response += "<h6>" + news['date'] + "</h6>";
response += "<p>" + news['content'] + "</p></li>";
}).then(()=>{
res.send(response);
})
});
Turn out it can be solved by this. I think the scope of var response makes it empty after executing the loop.

How can I connect to MongoDB using other device(s) accessing the locally hosted chat app?

I have a simple chat application built using sockets,MongoDB,Express.
The application works fine when hosted on my local machine (localhost:4000).
I am able to connect to MongoDB and send and receive messages.
Issue : But when I open the app on my phone browser using the PC IP address (e.g. 192.168.1.108:4000). I can see the index.html page , but unable to send and receive messages and load previous messages from mongodb.
//server.js
var express = require('express');
var app = express();
var server = require('http').createServer(app);
connections = [];
app.use(express.static(__dirname + '/public'));
server.listen(process.env.PORT || 4000);
console.log('Server Running');
app.get('/', function(req, res) {
res.sendFile(__dirname + '/index.html');
});
const mongo = require('mongodb').MongoClient;
const client = require('socket.io').listen(server).sockets;
// Connect to mongo
mongo.connect('mongodb://127.0.0.1/mongochat', function(err, db){
if(err){
throw err;
}
console.log('MongoDB connected...');
// Connect to Socket.io
client.on('connection', function(socket){
let chat = db.collection('chats');
// Create function to send status
sendStatus = function(s){
socket.emit('status', s);
}
// Get chats from mongo collection
chat.find().limit(100).sort({_id:1}).toArray(function(err, res){
if(err){
throw err;
}
// Emit the messages
socket.emit('output', res); //whenever we have to pass from server to client(index.html) , we do .emit()
});
// Handle input events
socket.on('input', function(data){
let name = data.name;
let message = data.message;
// Check for name and message
if(name == '' || message == ''){
// Send error status
sendStatus('Please enter a name and message');
} else {
// Insert message
chat.insert({name: name, message: message}, function(){
client.emit('output', [data]);
// Send status object
sendStatus({
message: 'Message sent',
clear: true
});
});
}
});
// Handle clear
socket.on('clear', function(data){
// Remove all chats from collection
chat.remove({}, function(){
// Emit cleared
socket.emit('cleared');
});
});
});
});
<!-- Index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
<title>MongoChat</title>
<style>
#messages{height:300px;}
</style>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 offset-md-3 col-sm-12">
<h1 class="text-center">
MongoChat
<button id="clear" class="btn btn-danger">Clear</button>
</h1>
<div id="status"></div>
<div id="chat">
<input type="text" id="username" class="form-control" placeholder="Enter name...">
<br>
<div class="card">
<div id="messages" class="card-block">
</div>
</div>
<br>
<textarea id="textarea" class="form-control" placeholder="Enter message..."></textarea>
</div>
</div>
</div>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<script>
(function(){
var element = function(id){
return document.getElementById(id);
}
// Get Elements
var status = element('status');
var messages = element('messages');
var textarea = element('textarea');
var username = element('username');
var clearBtn = element('clear');
// Set default status
var statusDefault = status.textContent;
var setStatus = function(s){
// Set status
status.textContent = s;
if(s !== statusDefault){
var delay = setTimeout(function(){
setStatus(statusDefault);
}, 4000);
}
}
// Connect to socket.io
var socket = io.connect('http://127.0.0.1:4000');
// Check for connection
if(socket !== undefined){
console.log('Connected to socket...');
// Handle Output
socket.on('output', function(data){
//console.log(data);
if(data.length){
for(var x = 0;x < data.length;x++){
// Build out message div
var message = document.createElement('div');
message.setAttribute('class', 'chat-message');
message.textContent = data[x].name+": "+data[x].message;
messages.appendChild(message);
messages.insertBefore(message, messages.firstChild);
}
}
});
// Get Status From Server
socket.on('status', function(data){
// get message status
setStatus((typeof data === 'object')? data.message : data);
// If status is clear, clear text
if(data.clear){
textarea.value = '';
}
});
// Handle Input
textarea.addEventListener('keydown', function(event){
if(event.which === 13 && event.shiftKey == false){
// Emit to server input
socket.emit('input', {
name:username.value,
message:textarea.value
});
event.preventDefault();
}
})
// Handle Chat Clear
clearBtn.addEventListener('click', function(){
socket.emit('clear');
});
// Clear Message
socket.on('cleared', function(){
messages.textContent = '';
});
}
})();
</script>
</body>
</html>
Try binding the http server on 0.0.0.0 through server.listen(process.env.PORT || 4000, '0.0.0.0') and also in your index.html you got
var socket = io.connect('http://127.0.0.1:4000');
which should actually be your internal ip.

trying to parse JSON data results in undefined error

I'm trying to load a local .json file in my NodeJS application and loop through the items, loading them in a ordered list. I've created my main js file and the model for the data, plus the main html page but I get a strange error. I receive document not defined in my data.js file:
document.getElementById('update').appendChild(makeUl(dataObject));
Here is my main js file, app.js:
var express = require('express' );
var app = express();
var bodyParser = require('body-parser');
app.use(express.static(__dirname+ '/client'));
app.use(bodyParser.json());
var Data = require('./models/data.js');
app.get('/', function(req,res){
res.send("Please use /api/data");
});
app.get('/api/data',function(req, res){
Data.getData(function(err, data){
if (err){
throw err;
}
res.json(data);
});
});
app.listen(5000);
console.log('Connected');
and here is my data.js file where I receive the error:
var dataObject = require("../jsondata/reduced_dataset.json");
function makeUL(array) {
// Create the list element:
var list = document.createElement('ul');
for(var i = 0; i < array.length; i++) {
// Create the list item:
var item = document.createElement('li');
// Set its contents:
item.appendChild(document.createTextNode(array[i]));
// Add it to the list:
list.appendChild(item);
}
// Finally, return the constructed list:
return list;
}
document.getElementById('update').appendChild(makeUL(dataObject));
I don't understand why I receive this error since I've linked it in the html page:
<html>
<head>
<title>Data Parsing</title>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="main.css">
</head>
<body>
<div id = "update"> </div>
<script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
<script src="app.js"></script>
<script src ="./models/data.js"></script>
</body>
</html>

Failed to load resource - Socket.IO

I have been trying my hand at node.js and socket.io, and following a tutorial. I keep getting an error from an application i am building. This is my server.js file:
var http = require('http');
var fs = require('fs');
var path = require('path');
var mime = require('mime');
var cache = {};
var chatServer = require('./lib/chat_server.js');
chatServer.listen(server);
//file doesn't exist
function send404(response) {
response.writeHead(404, {'Content-Type': 'text/plain'});
response.write('Error 404: resource not found.');
response.end();
}
//handles serving file data
function sendFile(response, filePath, fileContents) {
response.writeHead(
200,
{"content-type": mime.lookup(path.basename(filePath))}
);
response.end(fileContents);
}
//cache static files to memory
function serveStatic(response, cache, absPath) {
if (cache[absPath]) {
sendFile(response, absPath, cache[absPath]);
} else {
fs.exists(absPath, function(exists) {
if (exists) {
fs.readFile(absPath, function(err, data) {
if (err) {
send404(response);
}
else {
cache[absPath] = data;
sendFile(response, absPath, data);
}
});
}
else {
send404(response);
}
});
}
}
var server = http.createServer(function(request, response) {
var filePath = false;
if (request.url == '/') {
filePath = 'public/index.html';
}
else {
filePath = 'public' + request.url;
}
var absPath = './' + filePath;
serveStatic(response, cache, absPath);
});
server.listen(3001, function() {
console.log("Server listening on port 3001.");
});
This is my index.html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Chat</title>
<meta name="description" content="An interactive chat application using websockets.">
<link rel="stylesheet" href="/stylesheets/style.css">
</head>
<body>
<div id='content'>
<div id='room'></div>
<div id='room-list'></div>
<div id='messages'></div>
<form id='send-form'>
<input id='send-message' />
<input id='send-button' type='submit' value='Send'/>
<div id='help'>
Chat commands:
<ul>
<li>Change nickname: <code>/nick [username]</code></li>
<li>Join/create room: <code>/join [room name]</code></li>
</ul>
</div>
</form>
</div>
<script src="[localserver here]:3001/socket.io/socket.io.js" type="text/javascript"></script>
<script src="/javascripts/jquery-1.8.3.min.js" type="text/javascript"></script>
<script src="/javascripts/chat.js" type="text/javascript"></script>
<script src="/javascripts/chat_ui.js" type="text/javascript"></script>
</body>
</html>
Upon loading "[localserver here]:3001" from the browser, the index page appears with the ensuing CSS. But when i try an event, like sending a message, i get this error:
Error 404: resource not found.
I right-clicked and inspected element from my Chrome browser and got this two messages:
Failed to load resource: the server responded with a status of 404 (Not Found) "[localserver here]:3001/socket.io/socket.io.js"
Uncaught ReferenceError: io is not defined "[localserver here]:3001/javascripts/chat_ui.js:26"
This is line 26 from my chat_ui.js file:
var socket = io.connect('[localserver here]:3001');
$(document).ready(function() {
var chatApp = new Chat(socket);
socket.on('nameResult', function(result) {
var message;
if (result.success) {
message = 'You are now known as ' + result.name + '.';
} else {
message = result.message;
}
$('#messages').append(divSystemContentElement(message));
});
socket.on('joinResult', function(result) {
$('#room').text(result.room);
$('#messages').append(divSystemContentElement('Room changed.'));
});
socket.on('message', function (message) {
var newElement = $('<div></div>').text(message.text);
$('#messages').append(newElement);
});
socket.on('rooms', function(rooms) {
$('#room-list').empty();
for(var room in rooms) {
room = room.substring(1, room.length);
if (room != '') {
$('#room-list').append(divEscapedContentElement(room));
}
}
$('#room-list div').click(function() {
chatApp.processCommand('/join ' + $(this).text());
$('#send-message').focus();
});
});
setInterval(function() {
socket.emit('rooms');
}, 1000);
$('#send-message').focus();
$('#send-form').submit(function() {
processUserInput(chatApp, socket);
return false;
});
})
I have tried all sorts. Initially line 26 was var socket = io.connect(); and i changed it to the one above. I also changed the directory of socket.io.js in the index.html file from:
to
...as i thought this was the problem, but it is still giving me the same error.
Please how do i resolve this?
(PS - I am using Brackets as my IDE for node.js development. Also, i used "[localserver]" to indicate the localhost)
Try this:
<script type="text/javascript" src='http://localhost:3001/socket.io/socket.io.js'>
</script>
<script type="text/javascript">
var socket = io.connect('http://localhost:3001');
socket.on('connect',function(){
console.log("connect");
});
</script>
It must help you.
The line chatServer.listen(server); should be after you run your server.
chartServer is listening to the server but that one is not running yet.
Try to move this line:
chatServer.listen(server);
to the end of your script server.js

oAuth Fails: Is not allowed … Access-Control-Allow-Origin

what's wrong here?
OPTIONS https://twitter.com/oauth/request_token 401 (Unauthorized)
jsOAuth-1.3.4.js:483 XMLHttpRequest cannot load
https://twitter.com/oauth/request_token. Origin "http://localhost:8080"
is not allowed by Access-Control-Allow-Origin.Object
<!DOCTYPE html>
<html>
<head>
<!--
A simple example of PIN-based oauth flow with Twitter and jsOAuth.
This is mostly based on/copied from <http://log.coffeesounds.com/oauth-and-pin-based-authorization-in-javascri>.
Get jsOAuth at <https://github.com/bytespider/jsOAuth/downloads>
-->
<meta charset="utf-8">
<title>jsOauth test</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript" src="jsOAuth-1.3.4.js"></script>
<style type="text/css" media="screen">
</style>
<script>
$(document).ready(function() {
var options = {
consumerKey: 'YOUR_CONSUMER_KEY',
consumerSecret: 'YOUR_CONSUMER_SECRET'
};
var requestParams;
var accessParams;
var oauth = OAuth(options);
oauth.get('https://twitter.com/oauth/request_token',
function(data) {
console.dir(data);
window.open('https://twitter.com/oauth/authorize?'+data.text);
requestParams = data.text
},
function(data) { alert('darn'); console.dir(data) }
);
$('#pinbutton').click(function() {
if ($('#pin').val()) {
oauth.get('https://twitter.com/oauth/access_token?oauth_verifier='+$('#pin').val()+'&'+requestParams,
function(data) {
console.dir(data);
// split the query string as needed
var accessParams = {};
var qvars_tmp = data.text.split('&');
for (var i = 0; i < qvars_tmp.length; i++) {;
var y = qvars_tmp[i].split('=');
accessParams[y[0]] = decodeURIComponent(y[1]);
};
oauth.setAccessToken([accessParams.oauth_token, accessParams.oauth_token_secret]);
getHomeTimeline();
},
function(data) { alert('poop'); console.dir(data); }
);
}
});
function getHomeTimeline() {
oauth.get('https://api.twitter.com/1/statuses/home_timeline.json',
function(data) {
entries = JSON.parse(data.text);
var html = [];
for (var i = 0; i < entries.length; i++) {
html.push(JSON.stringify(entries[i]));
};
$('#timeline').html(html.join('<hr>'));
},
function(data) { alert('lame'); console.dir(data); }
);
}
});
</script>
</head>
<body>
<h1>jsOauth test</h1>
When you get a PIN, enter it here.
<input id="pin" type="text" value=""><button id='pinbutton'>Save</button>
<div id="timeline">
</div>
</body>
</html>
I could give you the answer, but what you're doing is against the Twitter API Terms of Service. OAuthing in JavaScript exposes the secret credentials to anyone who visits the site and that is A Bad Thing. Please do this on your back-end.

Categories

Resources