Node.js server responding with javascript file, not main .html? - javascript

I have a simple node.js server which is meant to respond to GET requests at the address http://localhost:3000/hi/ with my index.html document, and I cannot figure out why it is reading/responding with an (index) and index.js.
My function which works with router objects is:
const http = require('http');
const path = require('path');
const fs = require('fs');
let contacts = {
"1234": {
id: "1234",
phone: "77012345678",
name: "Sauron",
address: "1234 Abc"
},
"4567": {
id: "4567",
phone: "77012345678",
name: "Saruman",
address: "Orthanc, Isengard"
},
};
let loadStatic = (req, res) => {
res.writeHead(200, {'Content-Type': 'text/html'});
fs.readFile('./index.html', null, (err,data) => {
if (err) {
return console.log('error');
} else {
res.write(data);
}
res.end();
});
}
let routes = [
{
method: 'GET',
url: /^\/contacts\/[0-9]+$/,
run: getContact
},
{
method: 'DELETE',
url: /^\/contacts\/[0-9]+$/,
run: deleteContact
},
{
method: 'GET',
url: /^\/contacts\/?$/,
run: getContacts
},
{
method: 'POST',
url: /^\/contacts\/?$/,
run: createContact
},
{
method: 'GET',
url: /\/hi\//,
run: loadStatic
},
{
method: 'GET',
url: /^.*$/,
run: notFound
}
];
let server = http.createServer((req, res) => {
let route = routes.find(route =>
route.url.test(req.url) &&
req.method === route.method
);
route.run(req, res);
});
server.listen(3000);
Request URL: http://localhost:3000/hi/index.js
Request Method: GET
Status Code: 200 OK
Remote Address: [::1]:3000
Referrer Policy: no-referrer-when-downgrade
Connection: keep-alive
Content-Type: text/html
Date: Mon, 20 Aug 2018 23:41:45 GMT
Transfer-Encoding: chunked
Above is the response as processed by google chrome browser. I have no idea first of all, what (index) is - it contains all my html script, along with index.js which is also sent along (presumably with the html doc), which is the name of the javascript file that's supposed to be controlling the DOM. Both contain the html script, which is not right, the .js should be different, and it attempts to read the .js first. Also, the error in the console says "unexpected '<'" which should be obvious since it's trying to read a .js file which contains nothing but .html script. I am still very new to this, and can't find an answer. Thanks for reading, and hopefully revising!
**EDIT - I added more pertinent code to the server script. Lots of redacted functions, but those all work fine. It's this one request that isn't. index.html, index.js (this file controls the DOM and gets script tags in index.html), and newserver.js (name of this file) are in the same folder on my desktop. Hope that helps.

index.js is not "sent along" with index.html as you seem to think. The browser first requests /hi. When you send the content for that HTML file, the browser then parses that HTML file and for any <script src="xxx"> tags it finds in the HTML, the browser, then makes a separate request to your server for whatever the src file is in the script tag such as index.js.
Because you don't have a route for /index.js, it will match your notfound route (which you don't show the code for). FYI, your notfound routes should probably return a 404 status as this makes things a bit easier to debug (there will be 404 errors in the browser console which are easy to see).
You will need a route for all resources that your HTML files refer to (scripts, css files, images, etc...). node.js does not serve any files by default (unlike some other web servers). It only serves the files you specifically write routes for and write code to send.
It is possible to write a generic route that will serve any file in a specific directory that exactly matches a request. The Express framework has such as feature and is called express.static(). It is very useful for serving static resources that only need a static file sent. If you're going to continue to write your own http framework and not use one that's already been built, you will probably want to write such a static matcher. It is important, however, that you point a static file matcher at a directory that only contains public files so people can't inadvertently get access to private server files. And, one has to prevent things like .. or root paths being in the URL too.

Related

I'm making a Choropleth Map of the United States and its counties. The first map I used which was the world map worked fine. The new map doesn't work [duplicate]

I'm trying to make a request in a local file, but I don't know when I try to do on my computer show me an error. Is possible make a fetch to a file inside your project?
// Option 1
componentDidMount() {
fetch('./movies.json')
.then(res => res.json())
.then((data) => {
console.log(data)
});
}
error: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 at App.js: 10 --> .then(res => res.json())
// Option 2
componentDidMount() {
fetch('./movies.json', {
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
})
.then( res => res.json())
.then((data) => {
console.log(data);
});
}
error1: GET http://localhost:3000/movies.json 404 (Not Found) at App.js:15 --> fetch('./movies.json', {
error2: Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0 at App.js: 10 --> .then(res => res.json())
// This works
componentDidMount() {
fetch('https://facebook.github.io/react-native/movies.json')
.then( res => res.json() )
.then( (data) => {
console.log(data)
})
}
Try to place your json file in the public folder like so :
public/movies.json
and then fetch using
fetch('./movies.json')
or
fetch('movies.json')
I have experienced the same problem previously. When I place the json file in the public folder, problem is solved.
When using fetch, React normally reads asset/resources files in the public folder.
You are trying to serve a static file with a fetch command, which inherently requires the file to be served by a server. To resolve the issue, you have a few options available to you. I am going to outline the two that are most commonly suggested for such a thing:
Use Node.js and something like expressjs to host your own server that serves the file you want to fetch. While this procedure might require more effort and time, it is certainly more customizable and a good way to learn and understand how fetching from a backend works.
Use something like Chrome Web Server to easily set up a very simple server to serve your file on your local network. Using this method, you have very little control over what you can do with said web server, but you can quickly and easily prototype your web application. However, I doubt there's a way to move this method to production.
Finally, there are other options where you can upload one or more files online and fetch them from an external URL, however this might not be the optimal strategy.
Your JSON file needs to be served by the server so you need the express server (or any other). In this example we are using express.
Note: you can also download git repo
App.js File
import React, { Component } from 'react';
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: null
};
}
componentDidMount() {
const myHeaders = new Headers({
"Content-Type": "application/json",
Accept: "application/json"
});
fetch("http://localhost:5000/movie", {
headers: myHeaders,
})
.then(response => {
console.log(response);
return response.json();
})
.then(data => {
console.log(data);
this.setState({ data });
});
}
render() {
return <div className="App">{JSON.stringify(this.state.data)}</div>;
}
}
export default App;
server.js
var express = require("express");
var data = require('./movie.json'); // your json file path
var app = express();
app.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.get("/movie", function(req, res, next) {
res.send(data);
});
app.listen(5000, () => console.log('Example app listening on port 5000!'))
I was encountering the same error and there are two changes I made in my code to get rid of the error. Firstly, you don't need an express server to serve your files you can read data from a local json file inside your public folder in your create-react-app directory.
const getData=()=>{
fetch('data.json',{
headers : {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
}
)
.then(function(response){
console.log(response)
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
}
useEffect(()=>{
getData()
},[])
First, as suggested in some of the answers above ensure that your json file is inside the public folder and the path parameter inside the fetch function is correct as above. Relative paths didn't work for me.
Second, set the headers as shown. Removing the headers part from my fetch call was still giving me this error.
a simple solution to this is to use live server extension (if you use vs code)
Say that i have the following file test.html
<html>
<head>
<meta charset="UTF-8" />
</head>
<body>
<script>
var depdata;
depdata = fetch("test1.geojson")
.then((data) => {
return data;
});
depdata.then(function(data) {console.log(data)})
</script>
</body>
</html>
When access the file in the firefox through file://... I get the following error:
Cross-Origin Request Blocked:....
When I followed the error on firefox I got the following explanation
CORS requests may only use the HTTPS URL scheme, but the URL specified by the request is of a different type. This often occurs if the URL specifies a local file, using a file:/// URL.
To fix this problem, simply make sure you use HTTPS URLs when issuing requests involving CORS, such as XMLHttpRequest, Fetch APIs, Web Fonts (#font-face), and WebGL textures, and XSL stylesheets.
So the as far as I understand we just need to access the test.html through HTTP. The most straight forward way around this problem was the python simple http server. In the terminal.
> cd directory of the project.
> python3 -m http.server 8000 --bind 127.0.0.1
Then in the browser:
http://localhost:8000/test.html
My go-to approach is to use express-generator to set up a quick local server, then run ngrok (free tier is fine) and point your app to the url it creates. This has the advantage of letting you easily test your fetching in the iOS simulator or Android emulator, as well as on a device not tethered to your computer. Plus, you can also send the url to people testing your app. Of course, there would need to be a way for them to manually input that url so the app could set it as the fetch endpoint.
I got it working rather very simple way - no express / webserver really needed. Just do :
import data from '../assets/data.json';
and use the json data like this (say if it is a JsonArray) :
data.map(movie ...
Do this in App.js or some other class extending React.Component,
The error
Unexpected token < in JSON at position 0
comes from the HTML file that is returned if the request is unsuccessful. The first element (at position 0) of an HTML file is typically a '<'. Instead of a JSON, an attempt is made to read in an HTML file.
You can find the returned HTML File in the Inspect Tool -> Network -> Erroneous file marked in red -> Reponse. There you can see what the specific error is. Example Error Message
To fix the error for me, it helped to move the file to be imported to the Public folder of my React project and then import it like this from a file in the 'src' folder: fetch('dataTemplate.json')
You can place your json file in the public folder. In your React component you can use userEffect (). You don't need Express.js for this case.
React.useEffect(() => {
fetch("./views/util/cities.json")
.then(function(response) {
return response.json();
})
.then(function(myJson) {
console.log(myJson);
});
});
To fetch local files, a good alternative:
npm install file-fetch
to read a file:
const fileFetch = require('file-fetch')
fileFetch('./public/user.json').then((res) => {
res.body.pipe(process.stdout)
})
See doc

HTTP/HTTPS Nodejs Serve Javascript with HTML

I have a very simple https Nodejs server that serves an index.html that includes a request for a Javascript file. I cannot seem to get the browser to recognize the Javascript file.
<html>
<head>
<script src="deviceMotion.js"></script>
</head>
<body>
</body>
</html>
For this example, the contents of deviceMotion.js are immaterial. When I load the page and check Crhome debug tools, I receive a syntax error in the first line of the Javascript file, saying
Uncaught SyntaxError: Unexpected token '<'
I look at the "javascript" file's contents only to see that it is exactly the same as my index.html. This leads me to believe that there is an issue with the way my Node HTTPS server is serving the Javascript. Likely, it is just serving the html twice, even though my console logs show 3 separate requests being made, and only 2 when I remove the script tag from index.html. Obviously, it is trying to request the Javascript file, but there is something not right.
Here is the code for my server app.js
const http = require('http');
const fs = require('fs');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) => {
console.log("request received");
console.log(req.headers.referer);
fs.readFile('./src/index.html', function (error, data) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.end(data);
});
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
My files are structured such that I have app.js in the same directory as a folder called "src" and I have index.html and deviceMotion.js under src.
How can I control what files I serve and when depending on incoming requests? How can I differentiate requests made in order to serve the right file? I have tried parsing req.baseUrl and req.path and both are undefined.
Your Node.js server always returns a HTML file and sets the content type to HTML, so when your website requests the JavaScript file, it returns a HTML file, causing the Uncaught SyntaxError: Unexpected token '<' error. To fix the error, don't set the content type and let the browser figure it out, and also modify the code to return the requested file.
I have written some possible code below. However, it will need to be modified to suit your file structure.
const server = http.createServer((req, res) => {
console.log("request received");
console.log(req.headers.referer);
fs.readFile('./' + req.url, function (error, data) {
res.end(data);
});
});

Can't load scripts because of node.js

I can't use <script src="node_modules/jquery/dist/jquery.min.js"></script>
in my index.html file because of:
Failed to load resource: the server responded with a status of 404 (Not Found)
http://localhost:8080/node_modules/jquery/dist/jquery.min.js
This happens because of my else statement in server file code:
var http = require('http')
var url = require('url')
var fs = require('fs')
var server = http.createServer((req, res) => {
let parsedUrl = url.parse(req.url, true)
if (parsedUrl.pathname === '/') {
console.log('home page')
fs.readFile('./index.html', (err, data) => {
res.writeHead(200, { 'Content-Type': 'text/html' })
res.end(data)
})
} else if (parsedUrl.pathname === '/readJson') {
console.log('read json')
fs.readFile('./data.json', (err, data) => {
res.writeHead(200, { 'Content-Type': 'application/json' })
res.end(data)
})
} else {
console.log('We can\'nt load any resources because of this statement')
res.writeHead(404)
res.end()
}
})
server.listen(8080)
I've read about how to fix this problem when using express module. Is there any way to solve the problem without using that module?
The easiest way would be to simply load jQuery from a CDN instead of serving it from your own server. This is a widely accepted best practice.
Example:
<script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
You can find various options for loading jQuery from a CDN here: https://code.jquery.com
If you create an HTTP server like in your code example and want it to serve jQuery, then you'd have to read the jquery.min.js using fs.readFile and serve its contents, just like you're doing with your data.json file.
I recommend the use a CDN instead. If you install the jQuery module you can use it for your back-end JavasSript. However you want to use it on the front-end. You are using NodeJS as web server to serve a HTML page. The http module doesn't know anything about other files because it only read the index.html.
So you might wanna search for a solution to read/serve a complete folder. Withing this folder, lets call it public, you can store you HTML, CSS and JS files that are public available. Since the HTTP module knows about the entire folder all files can be used on the front-end. This is also a good solution to separate your back-end en front-end JavaScript.

simple node.js example in aws lambda

I am trying to send a simple request with aws lambda.
My module structure is as follows:
mylambda
|-- index.js
|-- node_modules
| |-- request
I zip the file up and it is uploaded to lambda.
Then I invoke it, and it returns the following error. "errorMessage": "Cannot find module 'index'"
Here is the contents of the index.js file
var request = require('request');
exports.handler = function(event, context) {
var headers = { 'User-Agent': 'Super Agent/0.0.1', 'Content-Type': 'application/x-www-form-urlencoded' }
// Configure the request
var options = {
url: 'https://myendpoint',
method: 'POST',
headers: headers,
form: {'payload': {"text":""} }
}
// Start the request
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
console.log(body)
}
})
console.log('value1 =', event.key1);
context.succeed(event.key1); // Echo back the first key value
};
Any help is appreciated, Thanks
All working now, I had to increase the Timeout(s) seconds in advanced settings, as it was taking longer than 3 seconds.
Also I had to ensure my node modules were correctly installed. I had messed up the request module when trying to figure out what was wrong.
To reinstall the module, I deleted then re-installed request.
deleted node_modules
npm init
added the dependancies "request" : "*" in the package.json,
npm install. Compressed the zip and uploaded, all working now. :)
You have to zip and upload subfolders only, not a root folder. You have to zip following folders as per your example, then upload:
|-- index.js
|-- node_modules
|-- request
Task: Write an aws lamda function:
How I have see us doing:
We write code in aws editor and run that
Not running as expected, put a lot of consoles there(because we can't debug our code)
Wait for some seconds then see the consoles in another window, keep changing the windows until we resolve our problem
4.changing the windows takes a lot of time and effort.
why can't we?
write the code in our server (not aws editor) and then send that code to aws.
Yes, we can.
new Function (https://davidwalsh.name/new-function) Blessing in disguise
concept.
Sample code:
let fs = require('fs');
const aws = require("aws-sdk");
const s3 = new aws.S3(),
async = require('async');
aws.config = {
"accessKeyId": "xyz",
"secretAccessKey": "xyz",
"region": "us-east-1"
};
fs.readFile('path to your code file', 'utf-8', async (err, code) => {
if (err) return res.status(500).send({ err });
async function uploadToS3(docs) { (only this function has to go into aws editor)
let func = new Function('docs', "aws", "s3", 'async', `${code}`);
return func(docs, aws, s3, async);
}
let resp = await uploa`enter code here`dToS3(req.files.docs);(this line will call aws lambda function from our server)
return res.send({ resp });
});
Code which I have written in my file:
docs = Array.isArray(docs) ? docs : [docs]
let funArray = [];
docs.forEach((value) => {
funArray.push(function (callback) {
s3.upload({
Bucket: "xxx",
Body: value.data,
Key: "anurag" + "/" + new Date(),
ContentType: value.mimetype
}, function (err, res) {
if (err) {
return callback(err, null);
}
return callback(null, res);
});
});
});
return new Promise((resolve, reject) => {
async.parallel(funArray, (err, data) => {
resolve(data);
});
});
Benefit:
As the whole code will be written in our familiar IDE, it will be easy to debug.
Only two lines have to go into aws editor (isn't it easy).
quite easy to modify/update the code(as the code will in our repo, we may not even have to go to aws editor).
yes we can other third parties libraries, but the above thing is written in pure JavaScript, no third party library is utilized there.
Also, here you don't have to deploy your code.
Sometimes our libraries total size increased to 5 MB and AWS lambda editor stop supporting it.
It will resolve this problem as well, now we will send only the required function from a library, not the whole library
on an average an async library contains around 100s of functions, but we use 1-2 functions. So, now we will send only the function which we are going to use.
Note:
I searched this a lot but nowhere found this kind of thing.
The above piece of code will upload docs to the s3 bucket.

Linking css files to node.js server

So I have craeted a node.js server with two routes. I use the fs to get the html files from the views folder and then append them to the page. In those html files I have a normal link to the css file, which does not seem to work. Here is my node.js app:
var port = 1357;
var http = require('http'),
path = require('path'),
mime = require('mime'),
fs = require('fs');
var app = http.createServer( function(req, res) {
if (req.url === '/home') {
fs.readFile('views/index.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
}
else if (req.url === '/about') {
fs.readFile('views/about.html', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/html'});
res.write(page);
res.end();
});
}
else {
res.writeHead(301,
{Location: '/home'}
);
res.end();
}
});
app.listen(port);
console.log('Server running on port: ' + port)
In the html files I have:
<link rel="stylesheet" type="text/css" href="./styles/styles.css">
It does not work. In chrome's console I get "Resource interpreted as Stylesheet but transferred with MIME type text/html. "
You defined 2 routes: /home and /about. You also defined that anything apart from these two routes should default to an HTTP redirect to the /home route, and this is what causes the problem.
When the browser encounters the link to the css file, it requests the following URL: /styles/styles.css. the server receives this URL and since it doesn't match the two defined routes it will go into the else statement which will send a redirect to /home, so your browser, asking for a css file, will only receive the html page located in /home.
To fix this, you might need to add a new rule for your css file:
else if (req.url === '/styles/styles.css') {
fs.readFile('styles/styles.css', function(err, page) {
res.writeHead(200, {'Content-Type': 'text/css'});
res.write(page);
res.end();
});
}
Of course, if you have more css files you need to manage a specific folder instead of files. I suppose you're doing this to learn Node, because if you don't you might want to use express which is a Node ready to use web server that will save you lot of time.
When the client (the browser) asks the server for /styles/styles.css the server responds with 301 Moved Permanently and Location: '/home'.
The browser then asks for /home and gets an HTML document, which is not a stylesheet.
You have to give the browser the stylesheet when it asks for it.
static assets (as in your stylesheets) wont be served automatically. So what happens is that it falls through and lands at the 301 redirect to /home, where you serve text/html.
If you want to serve css that way, add a rule req.url==="/styles/styles.css"
Generally, I would recommend using a routing lib like express or koa. Or as minimum, connect. They make it easy to hook in features called middleware and enable you to make everything in a directory (like /public) serve static content with one rule.

Categories