When I serve an html file, having some javascript, from my nodejs web server I get different results, compared to when I include the same javascript from an external source. I have verified that directly opening the html file with the javascript inline or external source works the same, as expected.
In the example below I get "Modified header" in h1 tag, whereas with javascript as external source I get "Unmodofied header" in h1 tag.
Can somebody explain how to rectify the problem? Thanks.
Code for nodejs web server:
var http = require('http')
var fs = require('fs')
http.createServer(function (request, response) {
fs.readFile('htmlfile.html', function(err, data) {
response.writeHead(200, {'Content-Type': 'text'})
response.write(data)
response.end()
})
}).listen(8081)
htmlfile.html is as follows:
<html>
<body>
<h1 id = "header"> Unmodified header</h1>
<!-- <script src="populate_header.js"></script> -->
<script>
function populate_header () {
document.getElementById("header").innerHTML = "Modified header"
}
populate_header ()
</script>
</body>
</html>
In a nutshell, your http server is not configured to send populate_header.js to the browser when the browser asks for it.
When you do this in your HTML file:
<script src="populate_header.js"></script>
You're telling the browser to send your web server a request for a resource named populate_header.js. But your web server does not have a request handler that looks at what file is being requested and serve that specific resource. Your web server always sends htmlfile.html no matter what resource is being requested. So, the browser asks for a script file and gets an HTML file (causing it to basically just ignore it). Thus, your Javascript in populate_header.js is never delivered to the browser and thus the script in it never runs.
When you include the script inline, the Javascript is delivered with the HTML and works just fine without requiring another route on your web server.
A node.js web server serves NO files at all by default. It only serves files that you create a route handler for. It is possible to create a single route that will serve lots of static files (when using the Express framework, express.static() does exactly that). But, by default, it does not serve any files.
As soon as you need more than one route handler, I would recommend using a very simple framework like ExpressJS because it will save you a lot of time and is very lightweight. But, if you were going to add a new route handler to your existing little web server, you could do so like this:
var http = require('http')
var fs = require('fs')
http.createServer(function (request, response) {
if (request.method === "GET") {
let fname;
// Look at what resource was requested and match that up
// with the appropriate file name
// DO not accept any resource requested because that could open up
// your server for people to request your actual server code files
switch(request.url) {
case "/":
fname = "htmlfile.html";
break;
case "/populate_header.js":
fname = "populate_header.js";
break;
default:
break;
}
if (fname) {
fs.readFile(fname, function(err, data) {
if (err) {
response.writeHead(404);
response.end();
} else {
response.writeHead(200, {'Content-Type': 'text'})
response.write(data)
response.end();
}
});
} else {
response.writeHead(404);
response.end();
}
}
}).listen(8081)
Here, you can see you're looking at request.url to see what exactly was requested and then sending that resource. It's also looking a request.method to only respond to GET requests. And, it's sending 404 responses when some other file is sent.
This would all be a lot simpler using the ExpressJS framework.
const express = require('express');
const app = express();
// look for matching static resources in the static_files subdirectory
app.use(express.static("static_files"));
// send the htmlfile.html file when / is requested
app.get("/", function(req, res) {
res.sendFile("static_files/htmlfile.html");
});
app.listen(8081);
Then, just locate all your static resources in a sub-directory below your main server directory named static_files and the Express framework will automatically look in that sub-directory for files that match the requested URL. This code adds one custom route for / that specifically sends the htmlfile.html file, and you can certainly customize that however you want.
For further discussion of how node.js servers don't send any files by default, see these other related answers:
Can't load local files when using NodeJS server
Resources not loading in express
ajax request gives a 404 with express server (chrome) loads successfully with firefox without a server?
How to get files above the server directory in Node.js
Related
I am building a website using NodeJS, and I deploy it to Heroku. But when I open the website, something went wrong. Here is the problem:
Code:
In the main source file of my web:
app.get('/', (req, res) => {
var data = {
rootURL: `${req.protocol}://${req.get('Host')}`,
};
res.render('home.html', data);
});
Then, in home.html, I include the following script:
<script type="text/javascript">
$.getJSON('{{rootURL}}'+'/about', {}, function(data){
// Code here is deleted for now.
}).fail(function(evt) {
// Code here is deleted for now.
});
</script>
Here I use hbs template, so {{rootURL}} is equal to the 'rootURL' property within the 'data' object rendered along with the 'home.html' page.
The '/about' is one of the APIs I designed for my web. It basically sends back something about the website itself and this information is wrapped in JSON.
Then, here comes the problem. The code works fine locally, and works well when I send HTTP request instead of HTTPS to Heroku. But if I send HTTPS request to Heroku, I'll get 'Mixed Content' Errors:
Errors I get in Chrome Console.
I then switched to 'Elements' tab in the developers tool, and I saw this:
The schema is HTTP, not HTTPS!
I'm very confused here. I just grab the 'protocol' property within the 'req' object, and fill in the template with it. So, I'm assuming if I enter '[my-website-name].herokuapp.com' with 'https' schema in my Chrome Browser, my nodeJS app deployed on Heroku should get 'https' for req.protocol. But Apparently it's not the case. What is wrong here?
I assume you don't actually have an SSL certificate? Heroku will be providing the HTTPS, but it will then translate it to normal HTTP internally when it hits your express endpoint, which is why it sees req.protocol as HTTP.
Is there any point in even providing the URL to getJSON? Why not just send it $.getJSON('/about', callback) and let the browser handle that?
Also, you haven't hidden your URL in that first image you uploaded, if that's what you were intending.
Heroku router is doing SSL termination, so no matter if you connect via http or https, you get http on your side. Original protocol is however set in X-Forward-Proto header. You need use this value.
I have been looking for a solution for this days ago... so basically I have 2 files: index.html and hellonode.js. Index.html has a div with text and a button that is supposed to make a request to hellonode.js when clicked. hellonode.js is supposed to receive requests and send a response to them.
hellonode.js:
var http= require('http');
function onRequest(request, response){
console.log("request has been received");
response.writeHead(200, {"Context-Type": "text/plain"});
response.write("<h1>response here!</h1>");
response.end();
}
http.createServer(onRequest).listen(8888);
console.log("server is running");
here is my index.html:
<!DOCTYPE html>
<html>
<head>
<script>
function loadXMLDoc() {
var xmlhttp;
xmlhttp = new XMLHttpRequest();
xmlhttp.onreadystatechange = function () {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById('myDiv').innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("GET", "hellonode.js", true);
xmlhttp.send();
}
</script>
</head>
<body>
<div id="myDiv">
<h2>content</h2>
</div>
<button type="button" onclick="loadXMLDoc()">Your response content should appear here</button>
</body>
</html>
Im using node js and a apache server (the binary version on Apachelounge.com), and put inside the htdocs folder those 2 files and then start my server, so when I access 192.168.0.102 from my other computers, I get the index.html screen. Everything is fine until here. When I click the button and send the request, the response that I receive is the entire javascript code of hellonode.js. Why is that happening? I have a feeling that my hellonode.js isnt even receiving my request, and that the index.html is just reading the hellonode's content and showing it istead of actually sending a request to it. Im new to this server-side stuff. Thanks.
Apache HTTPD is an HTTP server. The JavaScript you have written is also an HTTP server.
You are making the request to Apache HTTP for the file containing JavaScript program.
You should be running the JavaScript program via Node.js (e.g. from the command line of the server) and then using XMLHttpRequest to make the request to http://example.com:8888/
Note, you will then run into this error, so you will need to modify the JavaScript program to include CORS headers in the response. (Or you could use Apache's mod_proxy to let you make the request to Apache and then forward it to the JavaScript server).
This is happening because you are requesting the file hellonode.js using a GET request.
You need to set up and end point which you can send the request to. For example.
You need to setup a node server not an apache one.
You're correct. By sending an XHR request to hellonode.js, it's just sending a request to retrieve the file, and then returning all of the contents of said file.
It looks like what you're trying to do is run a Node server. You're going to need to configure your server to be able to serve the Node app, instead of running it through Apache (unless you want to serve a Node app with Apache).
To do it locally, you should run node hellonode.js, and it will spin up a server using Node, and be able to serve resources like you're expecting.
(Still, in that case, though, sending an XHR request to a file is just going to return the whole file without running it)
Nodejs is not intended to be run with apache. Apache shows your html page properly because it is meant to serve html pages -apart from PHP scripts-, however, is not intended to serve node scripts. So the request is returning your node scripts just as a plain text, like when you request a .css or .js file asset from a web page in the browser.
You must set up a node script explicitly invoking it with the node command:
node hellonode.js
Or in linux:
nodejs hellonode.js
Then, if your request and your server side script are properly coded, nodejs will actually listen to the request and send the proper response.
However, keep in mind that serving pages with node is not as straightforward than with apache, and educate yourself in services like nodemon or pm2 will sure pay you off.
As an example xmlhttp.open("GET", "hellonode.js", true); can be xmlhttp.open("GET", "http://www.thomas-bayer.com/sqlrest/", true);
Once you type in your terminal:
node hellonode.js
the Nodejs server is running on your current directory and hellonode.js file is used to display the result when you browser to : localhost:8888 in other words your hellonode.js file is playing the role of index.php in the classical php application.
To achieve what you want you can use the built-in http module, or use a framework like Expressjs or others.
I have a simple node.js server saved in a file called server.js, the code for which is below:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8010);
I am running this locally in command line (with node.js installed) by executing
node server.js
If I then access this in my browser (google chrome) with the URL my.local.IP.address:8010 it displays hello world successfully.
I am also creating a webpage that will execute this jQuery as soon as the page is loaded:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script>
$(document).ready(function(){
$.get("http://my.local.IP.address:8010/", function(){
alert("Success");
}).fail(function(err){
alert("Failed");
alert(JSON.stringify(err));
});
});
</script>
When I open this html file in my browser it always creates an alert box saying failed followed by this stringified JSON object as the error (I've formatted it so it is easier to read):
{
"readyState": 0,
"status" : 0,
"statusText": "error"
}
This happens no matter how many times I've tried while the node.js server is running locally. I have also tried to make an async XMLHTTP request function that does it myself, and this does not work either.
I know both the jQuery and the XMLHTTP function I made work correctly since if I call the functions on the URL https://httpbin.org/get it will return successfully.
Any ideas as to where I have gone wrong?
It's a cross domain issue. Browser thinks your page is not part of http://localhost:8081 server. You need to change server code as follows in order to make it work.
http.createServer(function (req, res) {
res.setHeader("Access-Control-Allow-Origin", "*");
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World\n');
}).listen(8010);
I guess it may be a cross domain issue, as you are using your IP address in the call, and localhost:8010 on the browser url to access your site. It is a problem common to ajax requests, and has nothing to do with Node.js
Try using the same url to access the site than the one you are targeting to.
See this similar issue with cross domain
I am making a single web app that takes information from MYSQL database and displays it on screen using AngularJS and NodeJS. I have set up a node.js server that gives out JSON file from a database. It works fine if I connect to it like this: 192.168.1.57:8888 which is my home server ip or remote connecting my server and using localhost:8888. Doing this downloads the JSON file on my computer.
However. If I'm using javascript to get JSON file from the server it gives me this error:
GET http://localhost:8888/ net::ERR_CONNECTION_REFUSED
I have tried connecting to the server with both AngularJS and JQuery and they both give the same error. I've also tried 127.0.0.1 and that doesn't work either. What can I do to fix it or can I do this with a better alternative way?
This is the server code in node.js
var http = require("http");
mysql = require("mysql");
var connection = mysql.createConnection({
user: "test",
password: "test",
database: "test"
});
http.createServer(function (request, response) {
request.on('end', function () {
connection.query('SELECT * FROM feedback;', function (error, rows, fields) {
response.writeHead(200, {
'Content-Type': 'x-application/json'
});
response.end(JSON.stringify(rows));
});
});
}).listen(8888);
this is the client side in angularJS:
(function(){
var app = angular.module('question', [ ]);
app.controller("ServerController", [ '$http', function($http){
$http.get("http://localhost:8888").success(function(data,status,headers,config){
console.log("success");
}).error(function(data,status,headers,config){
console.log("error");
});
} ]);
}
)();
Taking a guess at it, you're running into the Same Origin Policy, which requires that the page making the ajax request be in the same origin as the resource it's requesting (or that the server serving the resource supports CORS and allows the page's origin).
Two different ways this might be hitting you (I can't tell which, the question doesn't give enough information):
If the browser code is running in a page loaded from the file system, not via HTTP, then it's a cross-origin request because the protocols don't match (file: vs. http:).
If the page has not been loaded from localhost:8888, but instead from some other port on localhost, then the origins don't match because the port numbers are different.
I have created my first node js application: a simple webserver.
Here's the code:
// Load the http module to create an http server.
var http = require('http');
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.end("ARD Tagesschau\n");
});
// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);
// Put a friendly message on the terminal
console.log("Server running at http://127.0.0.1:8000/");
When I connect to the server via my browser I get the full string specified in my code as a web page.
Shouldn't the browser interpret that HTML code and display a link? Why do I get the full HTML code shown as plain text?
You have explicitly said that you are returning plain text, not HTML. The browser therefore treats it as plain text.
If you want HTML to be treated as HTML then say it is HTML:
{"Content-Type": "text/html"}
(Although you should send back an HTML document and not a fragment of HTML).
Following Code works for me:
var http = require('http');
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(function (request, response) {
response.writeHead(200, {"Content-Type": "text/html"});
response.end("ARD Tagesschau\n");
});
// Listen on port 8000, IP defaults to 127.0.0.1
server.listen(8000);
// Put a friendly message on the terminal
console.log("Server running at http://127.0.0.1:8000/");
You need to set the Headers. For more information check in Node API docs here.
Check the difference in your firebug or dev tools to understand how browser interprets differently based on Header Content-Type.