'argument hostname required' vhost - amazon-elastic-beanstalk

Having a weird issue with express vhost inside AWS. Every time I deploy I get an error in my EB log saying:
TypeError: argument hostname is required
at vhost (/var/app/current/node_modules/vhost/index.js:39:11)
at Object.<anonymous> (/var/app/current/app.js:554:9)
at Module._compile (internal/modules/cjs/loader.js:999:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1027:10)
at Module.load (internal/modules/cjs/loader.js:863:32)
at Function.Module._load (internal/modules/cjs/loader.js:708:14)
at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:60:12)
at internal/main/run_main_module.js:17:47
/var/app/current/node_modules/vhost/index.js:39
throw new TypeError('argument hostname is required')
^
If I have a look at the vhost module, index.js: line 36 we have the following:
function vhost(hostname, handle) {
if (!hostname) {
throw new TypeError('argument hostname is required')
}
if (!handle) {
throw new TypeError('argument handle is required')
}
if (typeof handle !== 'function') {
throw new TypeError('argument handle must be a function')
}
Not even any typechecking or anything on hostname like there is for handle, just checking if the value is passed in. Which it clearly is in the following code:
const app = express();
const register_app = express();
const nonadmin_app = express();
register_app.use(express.static(path.resolve(__dirname, './build/register')));
nonadmin_app.use(express.static(path.resolve(__dirname, './build/nonadmin')));
app.use(vhost('register.<eb-dev-url>.elasticbeanstalk.com/', register_app))
app.use(vhost('nonadmin.<eb-dev-url>.elasticbeanstalk.com/', nonadmin_app))
app.use(vhost('api.<eb-dev-url>.elasticbeanstalk.com/', api))
register_app.get('/register', (req, res) => {
res.sendFile(path.resolve(__dirname, './build/register', 'index.html'));
})
nonadmin_app.get('/nonadmin', (req, res) => {
res.sendFile(path.resolve(__dirname, './build/nonadmin', 'index.html'));
})
I'm not convinced this is a problem with vhost because when using register.localhost, nonadmin.localhost, or api.localhost when running this app locally using nodemon it works just fine. I also tried deploying with a .localhost suffix and still did not work.
Is there something I am missing in terms of AWS hostname config?

The answer was trailing slashes in the hostname argument.
Will raise a bug request.

Related

Error: connect ETIMEDOUT, how to solve it? using Node.js and MySQL2

I used Node.js and MySQL2. Working on MySQL workbench. Created virtual DB using Railway workbench. Schemas and tables are created. But showing `ETIMEDOUT error in the VS code's terminal when i try to run node index.js. What can i do?
db.js:
import mysql2 from 'mysql2';
export const db = mysql2.createConnection({
host: 'containers-us-west-174.railway.app',
user: 'user',
password: 'password',
database: 'railway'
})
index.js:
import express from 'express';
import authRoutes from './routes/auth.js';
import userRoutes from './routes/users.js';
import postRoutes from './routes/posts.js';
import dotenv from 'dotenv';
import cookieParser from 'cookie-parser';
import multer from 'multer';
dotenv.config();
const app = express();
app.use(express.json());
app.use(cookieParser());
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '../client/public/upload');
},
filename: function (req, file, cb) {
cb(null, Date.now() + '-' + file.originalname);
}
})
const upload = multer({ storage: storage })
app.post('/api/upload', upload.single('file'), function (req, res) {
const file = req.file;
res.status(200).json(file?.filename)
});
app.use('/api/auth', authRoutes);
app.use('/api/users', userRoutes);
app.use('/api/posts', postRoutes);
app.listen(8800, () => {
console.log('Connected wih backend!');
})
In my VS Code Terminal it is showing this error:
Connected wih backend!
node:events:505
throw er; // Unhandled 'error' event
^
Error: connect ETIMEDOUT
at Connection._handleTimeoutError (I:\EMON\Web-Development\FINALE\timeless-blog-f\api\node_modules\mysql2\lib\connection.js:189:17)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7)
Emitted 'error' event on Connection instance at:
at Connection._notifyError (I:\EMON\Web-Development\FINALE\timeless-blog-f\api\node_modules\mysql2\lib\connection.js:236:12)
at Connection._handleFatalError (I:\EMON\Web-Development\FINALE\timeless-blog-f\api\node_modules\mysql2\lib\connection.js:167:10)
at Connection._handleNetworkError (I:\EMON\Web-Development\FINALE\timeless-blog-f\api\node_modules\mysql2\lib\connection.js:180:10)
at Connection._handleTimeoutError (I:\EMON\Web-Development\FINALE\timeless-blog-f\api\node_modules\mysql2\lib\connection.js:193:10)
at listOnTimeout (node:internal/timers:559:17)
at processTimers (node:internal/timers:502:7) {
errorno: 'ETIMEDOUT',
code: 'ETIMEDOUT',
syscall: 'connect',
fatal: true
}
I was trying to deploting in railway. I'm using MySQL workbench.
In Railway deployment logs this error shows:
> api#1.0.0 start
> node index.js
node:internal/modules/cjs/loader:1239
return process.dlopen(module, path.toNamespacedPath(filename));
^
Error: /app/node_modules/bcrypt/lib/binding/napi-v3/bcrypt_lib.node: invalid ELF header
at Object.Module._extensions..node (node:internal/modules/cjs/loader:1239:18)
at Module.load (node:internal/modules/cjs/loader:1033:32)
at Function.Module._load (node:internal/modules/cjs/loader:868:12)
at Module.require (node:internal/modules/cjs/loader:1057:19)
at require (node:internal/modules/cjs/helpers:103:18)
at Object.<anonymous> (/app/node_modules/bcrypt/bcrypt.js:6:16)
at Module._compile (node:internal/modules/cjs/loader:1155:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1209:10)
at Module.load (node:internal/modules/cjs/loader:1033:32)
at Function.Module._load (node:internal/modules/cjs/loader:868:12) {
code: 'ERR_DLOPEN_FAILED'
}
npm WARN config production Use `--omit=dev` instead.
And deployment crashed!
Any solution?

Unable to track the issue this.stack.push(layer); in node.js

this is my code
usercontroller:-
const {hashSync,genSaltSync}=require('bcrypt');
const {create}=require('./user.service');
module.exports={
createUser:(req,res)=>{
const body=req.body;
const salt=genSaltSync(10);
body.password=hashSync(body.password,salt);
create(body,(error,results)=>{
if(error){
return res.status(500).json(
{
success:0,
message : "Database connection error"
}
);
}
return res.status(200).json({
status:200,
data:results
});
})
}
}
userservice:-
const pool=require("../config/database")
module.exports={
create: (data,callback)=>{
pool.query(
`insert into registration(firstName,lastName,gender,email,password,number)
values(?,?,?,?,?,?)`,
[
data.first_name,
data.last_name,
data.gender,
data.email,
data.password,
data.number
],
(error,results,fields) =>
{
if(error)
{
return callback(error);
}
else{
return callback(null,results);
}
}
);
}
}
userrouter:-
const {createUser} = require("../users/user.controller")
const {createUser}=require("./user.controller")
const router=require("express").Router;
router.post("/",createUser);
module.exports=router;
app.js
require("dotenv").config();
const express = require("express")
const app=express();
const userrouter=require('./users/user.router')
app.use("/api/users",userrouter);
app.listen(process.env.APP_PORT,()=>{
console.log("server up and running")
});
.env
APP_PORT=3000
DB_PORT=3306
DB_HOST=localhost
DB_USER=root
DB_PASSWORD=divyanshu123
MYSQL_DB=test
i am not able to run it getting error:-
[nodemon] 2.0.4
[nodemon] to restart at any time, enter rs
[nodemon] watching path(s): .
[nodemon] watching extensions: js,mjs,json
[nodemon] starting node app.js
C:\Users\Divyanshu Thakur\Desktop\Jwt\node_modules\express\lib\router\index.js:502
this.stack.push(layer);
^
TypeError: Cannot read property 'push' of undefined
at Function.route (C:\Users\Divyanshu Thakur\Desktop\Jwt\node_modules\express\lib\router\index.js:502:14)
at Function.proto. [as post] (C:\Users\Divyanshu Thakur\Desktop\Jwt\node_modules\express\lib\router\index.js:509:22)
at Object. (C:\Users\Divyanshu Thakur\Desktop\Jwt\users\user.router.js:4:8)
at Module._compile (internal/modules/cjs/loader.js:1133:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:1153:10)
at Module.load (internal/modules/cjs/loader.js:977:32)
at Function.Module._load (internal/modules/cjs/loader.js:877:14)
at Module.require (internal/modules/cjs/loader.js:1019:19)
at require (internal/modules/cjs/helpers.js:77:18)
at Object. (C:\Users\Divyanshu Thakur\Desktop\Jwt\app.js:4:18)
[nodemon] app crashed - waiting for file changes before starting...
Change this:
const router=require("express").Router;
to this:
const router=require("express").Router();
You have to actually call the factory function to create a new router. Your problem then occurs when you try to do:
router.post("/",createUser);
or:
app.use("/api/users",userrouter);
But, your object isn't actually a router.
Not sure if this is the source of your issue but this seems rather problematic:
const { createUser } = require("../users/user.controller")
const { createUser } = require("./user.controller")
That's from the userRouter file.

Unable to connect to MySql server from Node.js

I am new to MySQL and cannot seem to connect to the server from Node.js. Also, I am on windows, not UNIX.
I am able to connect to the server using sqlcmd logged into the user I created for node. I have also enabled TCP/IP and named pipes.
const express = require("express");
const mysql = require("mysql");
const app = express();
const sqlServer = mysql.createConnection({
server: "127.0.0.1",
port: "1433",
user: "MeetMe",
password: "dOI9Zham1f5xOJAvweUIvuWlc"
});
const SELECT_ALL_QUERY = "SELECT * FROM Accounts";
sqlServer.connect(function(err) {
console.log("Connected to sql server");
if (err) throw err;
});
app.get("/", (req, res) => {
sqlServer.query(SELECT_ALL_QUERY, function(err, results, fields) {
if (err) throw err;
console.log(results);
});
res.send("Hello world");
});
app.listen(4000);
console.log("Server running on port 4000");
The program always throws an error during sqlServer.connect().
C:\dev\Webapps\meet-me\server.js:16
if (err) throw err;
^
Error: read ECONNRESET
at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
--------------------
at Protocol._enqueue (C:\dev\Webapps\meet-me\node_modules\mysql\lib\protocol\Protocol.js:144:48)
at Protocol.handshake (C:\dev\Webapps\meet-me\node_modules\mysql\lib\protocol\Protocol.js:51:23)
at Connection.connect (C:\dev\Webapps\meet-me\node_modules\mysql\lib\Connection.js:119:18)
at Object.<anonymous> (C:\dev\Webapps\meet-me\server.js:14:11)
at Module._compile (internal/modules/cjs/loader.js:701:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:712:10)
at Module.load (internal/modules/cjs/loader.js:600:32)
at tryModuleLoad (internal/modules/cjs/loader.js:539:12)
at Function.Module._load (internal/modules/cjs/loader.js:531:3)
at Function.Module.runMain (internal/modules/cjs/loader.js:754:12)
MySQL's default port number is 3306.
Your createConnection options object mentions port 1433. That's the default port for Microsoft SQL server. Try removing the port element from that object. Or, if that doesn't work, change it to 3306.
I realized there is a difference in MicrosoftSQL and MySQL. Thank you for everyone that tried to help!

Logging all requests in Node.js/Express

In my small node.js application, using express, I wanted to log all the incoming requests, so I ended up with this:
var bodyParser = require('body-parser');
module.exports = function(app) {
app.set("port", 50001);
app.set("json spaces", 2);
app.use(bodyParser.json());
app.use(function (error, req, res, next) {
app.logger.info("received from "+req.get("X-Forwarded-For")+" : "+req.method+" "+req.originalUrl+" (Authorization: "+req.get("Authorization")+")");
//does not work if json is malformed
//app.logger.info("content :"+JSON.stringify(req.body));
if (error /*instanceof SyntaxError*/) {
res.status(400);
app.logger.error(error);
res.json({ error:{msg: error.message}});
} else {
next();
}
});
app.use(app.auth.initialize());
};
Unfortunately, I only get the logs via the app.logger.info line when there's an error (in my case a malformed JSON string in the body). What am I missing here?
Expressjs adapts its functionality based on what type of callback you give it (this is not common in JS libraries so it is not surprising that people get confused by it).
If you do this where your callback has four arguments:
app.use(function(error, req, res, next) {...});
then Express assumes this is an error-only middleware handler and will only be called when there are errors. In the express doc, see the section labeled Error-handling middleware. Note this specific part of that page:
Define error-handling middleware functions in the same way as other
middleware functions, except with four arguments instead of three,
specifically with the signature (err, req, res, next)):
And, here's a whole section of the documentation devoted to error handling middleware.
If you use just three arguments:
app.use(function(req, res, next) {...});
then, it is a normal middleware that is called when there are not errors. I'm not sure if they provide a single way to get both. But, certainly as a workaround, you could put your logging code into a function and then call that function from two separate middleware handlers, one for errors and one for non-errors.
Use morgan https://github.com/expressjs/morgan
Install morgan
$ npm install morgan
Include morgan in the index.js or app.js or server.js file (The file that pointed by the script tag in the package.json)
var morgan = require('morgan')
Then add below before all the app call.
app.use(morgan('combined'))
Complete example
var express = require('express')
var morgan = require('morgan')
var app = express()
app.use(morgan('combined'))
app.get('/', function (req, res) {
res.send('hello, world!')
})
A sample output line looks like this:
::1 - - [31/May/2021:09:03:14 +0000] "GET / HTTP/1.1" 200 2078 "-" "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36"
DEBUG='*' or DEBUG='express:router' environment variable
It does not show a lot of information about the request, but it does show the path and method, which might be enough for basic applications, and is convenient as it does not require any extra setup.
DEBUG='*' enables all logs and is slightly easier to type:
DEBUG='*' ./app.js
or the more specific DEBUG='express:router' is what you will generally want in a complex application with a lot of middleware, otherwise the DEBUG='*' could produce mountains of output:
DEBUG='express:router' ./app.js
E.g. with the hello world:
#!/usr/bin/env node
const express = require('express')
const app = express()
const port = 3000
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
Then as I play on the browser with different URLs I can see logs such as:
express:router dispatching GET / +3m
express:router query : / +0ms
express:router expressInit : / +0ms
express:router dispatching GET /asdf +10s
express:router query : /asdf +0ms
express:router expressInit : /asdf +0ms
finalhandler default 404 +3m
express:router dispatching GET /asdf?qwer=zxcv +17s
express:router query : /asdf?qwer=zxcv +0ms
express:router expressInit : /asdf?qwer=zxcv +0ms
finalhandler default 404 +17s
Documentation at: https://expressjs.com/en/guide/debugging.html
Tested on express 4.17.1.
npm install body-parser
npm install morgan-body
and use this snippet,
const express = require('express')
const morganBody = require("morgan-body")
const bodyParser = require("body-parser")
const app = express()
const port = 8888
// must parse body before morganBody as body will be logged
app.use(bodyParser.json());
// hook morganBody to express app
morganBody(app, {logAllReqHeader:true, maxBodyLength:5000});
app.get('/', (req, res) => {
res.send('Hello World!')
})
app.listen(port, () => {
console.log(`Example app listening at http://localhost:${port}`)
})
You can just use grackle_tracking npm library to easily log all your traffic out to the console or log it to your database - also tracks uncaugt/caught errors - you can toggle it on/off easily for different environments as well since it's just
grackle_tracking.configure({...configuration...});
app.use(grackle_tracking.track);
so you can comment out both or just the bottom line for environments/users you don't want to track
https://www.getgrackle.com/libraries#grackle_tracking_overview
You could use try/catch
try {
var jsonBody = JSON.stringify(req.body);
app.logger.info("content :" + jsonBody);
} catch (err) {
app.logger.error("content error, error type: invalid json, error msg:" + err);
}

Node.JS JSON.parse error undefined

I tried to parse json file in node
but there always error
and I google it but cannot solve it .
Can you help me?
undefined:1
undefined
^
SyntaxError: Unexpected token u
at Object.parse (native)
at Object.<anonymous> (app.js:13:19)
at Module._compile (module.js:449:26)
at Object.Module._extensions..js (module.js:467:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Module.runMain (module.js:492:10)
at process.startup.processNextTick.process._tickCallback (node.js:244:9)
this's my code
var app = express();
var mongodb = require("mongoskin");
var fs = require('fs');
var content;
fs.readFile('./config/db.json', function read(err, data) {
if (err) {
throw err;
}
content = data;
});
var config = JSON.parse(content);
app.get('/', function(req, res){
res.send(config.left);
});
app.listen(process.env.VCAP_APP_PORT || 3000);
and the db.json is this. As you can see, there are no errors.
{
"left": 3
}
readFile is asynchronous, so your JSON.parse line is called before you assign a value to content, and so content has its default value of undefined.
You have two options:
Move the logic using the data into the callback.
var app = express();
var mongodb = require("mongoskin");
var fs = require('fs');
fs.readFile('./config/db.json', function read(err, data) {
if (err) {
throw err;
}
var config = JSON.parse(data); // <=== Note I'm using `data`, not `content`; we don't need a `content` variable anymore
app.get('/', function(req, res){
res.send(config.left);
});
app.listen(process.env.VCAP_APP_PORT || 3000);
});
Use the synchronous version of readFile (which is readFileSync).
// ...
content = fs.readFileSync('./config/db.json');
var config = JSON.parse(content);
// ...
content is equal to undefined when you try to parse it.
You should parse your JSON data in the readFile callback or use readFileSync instead.
Also you should probably not throw from a callback.
This leads me to think that you have some misconceptions of how node.js works and I strongly recommend you read this