Im trying to test out node.js - node.js

so I just downloaded and installed node/npm and attempted to run a test with the following code.
const http = require(‘http’);
const hostname = ‘127.0.0.1’;
const port = 3000;
const server = http.createServer((req, res) => {
res.statusCode = 200;
res.setHeader(‘Content-Type’, ‘text/plain’);
res.end(‘Hello from NodeJS\n’);
});
server.listen(port, hostname, () => {
console.log(`Server running at http://${hostname}:${port}/`);
});
but the output gives me plenty of error messages (an identifier cant go after this identifier, this cant go here, unexpected, etc) I see a couple of things that could be wrong, but I'm new to this.

I would direct you to https://nodejs.dev/learn
You need to require the http module by doing const http = require('http');
Also your quotation marks are improper they must be single quotes, double quotes, or backticks. They cannot be whatever unicode character you have in there.

You are using some strange characters, this: ’
Try to use " or ' in module import, setHeader, ...

Related

It won't accept command line after first run

I ran my first server and seems fine except that it won't stop running. I cannot even type anything else in the command line. I will appreciate any help
Here is the code I ran
const http = require('http');
const hostname = '127.0.0.1';
const port = 3000;
const server = http.createServer((req, res) =>
{
res.statusCode = 200;
res.setHeader('Content-Type', 'text/plain');
res.end('In the name of Allah, the Most Gracious, the Most Merciful.');
});
server.listen(port, hostname, () =>
{
console.log(`Server running at http://${hostname}:${port}/`);
});
But the problem is not the code, rather how to get back to this command line
$papus#QuantumOne MINGW64 /c/Projects/firstServer so that I can start retyping again on the command line without closing everything down and restart the whole process.
right now it gets stuck on Server running at http://127.0.0.1:3000 forever
Because it is a server and it is not supposed to stop after a time.
You can shut down by pressing ctrl + c
Or you can program a certain route that will kill it programatically (i did not say it should be done)
If you want to continue using the same terminal you can run the server in background (on unix systems it is done by adding & at the end of the start command)
You can also look at process manager for nodejs server like pm2

fs.createReadStream getting a different path than what's being passed in

I'm using NodeJS on a VM. One part of it serves up pages, and another part is an API. I've run into a problem, where fs.createReadStream attempts to access a different path than what is being passed into the function. I made a small test server to see if it was something else in the server affecting path usage, for whatever reason, but it's happening on my test server as well. First, here's the code:
const fs = require('fs');
const path = require('path');
const csv = require('csv-parser');
const readCSV = (filename) => {
console.log('READ CSV GOT ' + filename); // show me what you got
return new Promise((resolve, reject) => {
const arr = [];
fs.createReadStream(filename)
.pipe(csv())
.on('data', row => {
arr.push(row);
})
.on('error', err => {
console.log(err);
})
.on('end', () => {
resolve(arr);
});
}
}
// tried this:
// const dir = path.relative(
// path.join('path', 'to', 'this', 'file),
// path.join('path', 'to', 'CONTENT.csv')
// );
// tried a literal relative path:
// const dir = '../data/CONTENT.csv';
// tried a literal absolute path:
// const dir = '/repo/directory/server/data/CONTENT.csv';
// tried an absolute path:
const dir = path.join(__dirname, 'data', 'CONTENT.csv');
const content = readCSV(dir)
.then(result => {console.log(result[0]);})
.catch(err => {console.log(err);});
...but any way I slice it, I get the following output:
READCSV GOT /repo/directory/server/data/CONTENT.csv
throw er; // Unhandled 'error' event
^
Error: ENOENT: no such file or directory, open '/repo/directory/data/CONTENT.csv'
i.e., is fs.createReadStream somehow stripping out the directory of the server, for some reason? I suppose I could hard code the directory into the call to createReadStream, maybe? I just want to know why this is happening.
Some extra: I'm stuck on node v8.11, can't go any higher. On the server itself, I believe I'm using older function(param) {...} instead of arrow functions -- but the behavior is exactly the same.
Please help!!
Code is perfect working.
I think you file CONTENT.csv should be in data folder like "/repo/directory/data/CONTENT.csv".
I'm answering my own question, because I found an answer, I'm not entirely sure why it's working, and at least it's interesting. To the best of my estimation, it's got something to do with the call stack, and where NodeJS identifies as the origin of the function call. I've got my server set up in an MVC pattern so my main app.js is in the root dir, and the function that's being called is in /controllers folder, and I've been trying to do relative paths from that folder -- I'm still not sure why absolute paths didn't work.
The call stack goes:
app.js:
app.use('/somepath', endpointRouter);
...then in endpointRouter.js:
router.get('/request/file', endpointController.getFile);
...then finally in endpointController.js:
const readCSV = filename => {
//the code I shared
}
exports.getFile = (req, res, next) => {
// code that calls readCSV(filename)
}
...and I believe that because Node views the chain as originating from app.js, it then treats all relative paths as relative to app.js, in my root folder. Basically when I switched to the super unintuitive single-dot-relative path: './data/CONTENT.csv', it worked with no issue.

Open up terminal/shell on remote server via tcp request

I have this:
const http = require('http');
const cp = require('child_process');
const server = http.createServer((req,res) => {
const bash = cp.spawn('bash');
req.pipe(bash.stdin, {end:false);
bash.stdout.pipe(res);
bash.stderr.pipe(res);
});
server.listen('4004');
when I hit the server with:
curl localhost:4004
and I type bash commands, nothing gets outputed to my console, anybody know why?
Note: To address security I plan to run this in a docker container, use https/ssl, and implement authentication (any recommendations on auth schemes lmk).
More importantly, I am looking for shell prompts to appear ... apparently bash by itself doesn't open up a shell/prompt?
It is possible to do this "over the web" so to speak. However, your approach will not work, because you are mixing paradigms (batch vs. interactive), and you are missing large chunks of setup that's needed to run terminal applications.
Normally I would show you how to program this, however, that's really involved. Have a look at:
https://github.com/chjj/tty.js
and,
https://github.com/xtermjs/xterm.js
as starting points to create your solution.
Both are usable directly from node.js to serve up terminal applications over HTTP.
This is a partial answer, but I started a bounty because I am looking for something better. I was able to create something rudimentary with TCP like so:
const net = require('net'); // !use net package not http
const cp = require('child_process');
const server = net.createServer(s => {
const bash = cp.spawn('bash');
s.pipe(bash.stdin, {end:false});
bash.stdout.pipe(s);
bash.stderr.pipe(s);
});
server.listen('4004');
not sure why it won't work with HTTP though. I connect to it using netcat:
nc localhost 4004
but this isn't opening a terminal, just a bash process. the experience is not ideal, as described here:
https://unix.stackexchange.com/questions/519364/bash-shell-modes-how-to-pipe-request-to-shell-on-remote-server
however I am looking to replicate the shell experience you have when you do something like:
docker exec -ti <container> /bin/bash
when I run my script it "works", but I don't get any shell prompts or anything like that. (One way to solve this might be with ssh, but I am trying to figure out a different way).
You can connect to an http server with telnet. It depends on how you're starting the http server. Here's an example
Start an http server with the npm package http-server
npm install -g http-server
cd ~/ <Any directory>
http-server
Now seperately start a telnet session
telnet localhost 8080
OR
nc localhost 8080
And then type something like GET /
Use the telnet client instead of nc
Check this: https://www.the-art-of-web.com/system/telnet-http11/
Update: Running an ssh server over nodejs. It allows you to run an ssh server
I found this at https://github.com/mscdex/ssh2
var fs = require('fs');
var crypto = require('crypto');
var inspect = require('util').inspect;
var ssh2 = require('ssh2');
var utils = ssh2.utils;
var allowedUser = Buffer.from('foo');
var allowedPassword = Buffer.from('bar');
var allowedPubKey = utils.parseKey(fs.readFileSync('foo.pub'));
new ssh2.Server({
hostKeys: [fs.readFileSync('host.key')]
}, function(client) {
console.log('Client connected!');
client.on('authentication', function(ctx) {
var user = Buffer.from(ctx.username);
if (user.length !== allowedUser.length
|| !crypto.timingSafeEqual(user, allowedUser)) {
return ctx.reject();
}
switch (ctx.method) {
case 'password':
var password = Buffer.from(ctx.password);
if (password.length !== allowedPassword.length
|| !crypto.timingSafeEqual(password, allowedPassword)) {
return ctx.reject();
}
break;
case 'publickey':
var allowedPubSSHKey = allowedPubKey.getPublicSSH();
if (ctx.key.algo !== allowedPubKey.type
|| ctx.key.data.length !== allowedPubSSHKey.length
|| !crypto.timingSafeEqual(ctx.key.data, allowedPubSSHKey)
|| (ctx.signature && !allowedPubKey.verify(ctx.blob, ctx.signature))) {
return ctx.reject();
}
break;
default:
return ctx.reject();
}
ctx.accept();
}).on('ready', function() {
console.log('Client authenticated!');
client.on('session', function(accept, reject) {
var session = accept();
session.once('exec', function(accept, reject, info) {
console.log('Client wants to execute: ' + inspect(info.command));
var stream = accept();
stream.stderr.write('Oh no, the dreaded errors!\n');
stream.write('Just kidding about the errors!\n');
stream.exit(0);
stream.end();
});
});
}).on('end', function() {
console.log('Client disconnected');
});
}).listen(0, '127.0.0.1', function() {
console.log('Listening on port ' + this.address().port);
});
Your approaches are quite mixed, nonetheless, when ever you finally connect to the remote server do not use 'bash' as a method to start the connection, BASH is just born again shell with other commands & stuff in it,
Rather use some of the following program, command-line names: i.e :
~ $ 'gnome-terminal'
~ $ 'xterm'
there you will now be referencing a true program in the system, even kernel level C code has its own recognition of these, if not changed.

Node Express Server Get not getting the first '?' in a query

I am trying to make a get call to my node server using the following parameters
http://localhost:8080/products/?a=13214?b=awedf
I am getting the error: Cannot GET /products/?a=13214?b=awedf
When I remove the '?' before the letter 'a', I get the following query:
{ b: 'awedf' }
I want to be able to add the '?' and get the following query or something similar that gives me the following array:
{ a:13214, b: 'awedf' }
Here is the code I have:
var express = require('express'),
app = express();
var timeout = 0;
app.use(express.static(__dirname, '/'));
app.get('/products/:siteId', function(req, res) {
console.log(req.query);
res.json(products);
});
app.listen(8080);
console.log('Express listening on http://localhost:8080/');
var products = [
{"Product":"Product A"}
,{"Product":"Product B"}
];
EDIT:
I fixed it by changing the query parameters:
http://localhost:8080/product?a=13214&b=awedf
Instead of second ? add &. Parameters are separated with ampersand. Question mark indicates the beginning of query string
Also you don't need :siteId in the path. If you want to use :siteId, then your url would look like /products/1234?b=abc
req.params.siteId === 1234 and req.query.b === 'abc'
So you should replace the ? before b with & like this: http://localhost:8080/products/?a=13214&b=awedf
EDIT: Since you cannot modify the parameters and you already have /:siteId then you should be able to access the value for a like this: req.params.siteId.

How do I insert a newline in Node.js when using Heroku?

I'm trying to create a Node.js application on Heroku that will output 10 different ASCII faces (I already have the module needed for that). Using the Node tutorial on Heroku, I've set it up to output 10 faces. However, when I try to actually run the code, it puts all of the faces inline with each other. How should I try to make it so that the faces are outputted (if that's even a word) on their own lines?
My current index.js is as follows:
var express = require('express');
var app = express();
var cool = require('cool-ascii-faces');
app.set('port', (process.env.PORT || 5000));
app.get('/', function(request, response) {
var result = ''
var times = process.env.TIMES || 5
for (i=0; i < times; i++)
result += cool();
response.send(result);
});
app.listen(app.get('port'), function() {
console.log("Node app is running on port: " + app.get('port'))
})
I have a .env file already set up for Foreman to use (when testing locally) that contains the following:
TIMES=9
If you want to have a look at the output, head on over here.
TL;DR: How do I use newlines in Node?
I visited the site in question and did a View -> Source. There's no markup of any kind like HTML, BODY, etc. I assume that the browser then would interpret the output as HTML. This ought to work since we're using an HTML tag and a pair of PRE tags to indicate that if we see a hard return ('\n') then the browser should display it.
app.get('/', function(request, response) {
var result = '<html><pre>';
var times = process.env.TIMES || 5
for (i=0; i < times; i++)
result += cool() + '\n';
result += '</pre></html>';
response.send(result);
});
By default, the browser assumes that web servers send HTML.
HTML ignores newlines.
If you aren't sending HTML, you need to specify that by setting a different type:
response.header("Content-Type", "text/plain");
To actually send a newline, just concatenate '\n' to your string.

Resources