Im using the MERN stack + Heroku to deploy and want to host a static txt file at "myurl.com/file.txt".
My file.txt is in the client/build directory.
When I navigate to "myurl.com/file.txt" I get "Cannot GET /file.txt"
I know this is probably a newby question and a bit open ended, I have looked a bunch online but I'm struggling to figure this out. Thanks in advance!
Here is a code snippet of my server.js file.
If there is any other info you need pls ask!
const express = require('express');
const cors = require('cors');
const mongoose = require('mongoose');
require('dotenv').config();
const app = express();
const port = process.env.PORT || 5000;
app.use(cors());
app.use(express.json());
const uri = "my_mongodb_uri"; // of course here I have my actual URI, I know its not secure, I'll change it before it goes public :P
mongoose.connect(uri, { useCreateIndex: true, useNewUrlParser: true, useUnifiedTopology: true })
.then(connect => console.log('connected to mongodb'))
.catch(e => console.log('could not connect to mongodb', e))
const connection = mongoose.connection;
connection.once('open', () => { console.log("MongoDB database connection established successfully"); })
const matchesRouter = require('./routes/matches');
const usersRouter = require('./routes/users');
app.use('/matches', matchesRouter);
app.use('/users', usersRouter);
if(process.env.NODE_ENV === 'production'){
app.use(express.static('client/build'));
}
app.listen(port, () => {
console.log(`Server is running on port: ${port}`)
});
Related
I'm following a tutorial for setting up a React application with MongooseDB, Express etc. I'm using Postman for GET, POST. See code below (I've starred the password from the database string).
When I send GET HTTP://localhost:8001 it shows "hello world" which I expect.
When I send GET HTTP://localhost:8001/tinder/cards it hangs and eventually displays the error "Error: socket hang up".
When I send POST HTTP://localhost:8001/tinder/cards it hangs and eventually gives a 500 Internal Server error.
Can anyone point me in the direction of where to debug please? I'm guessing the connection works as when I send GET HTTP://localhost:8001 it shows "hello world".
Thanks again.
import express from 'express'
import mongoose from 'mongoose'
import Cards from './dbCards.js'
import Cors from 'cors'
// App Config
const app = express();
const port = process.env.PORT || 8001
const connection_url = `mongodb+srv://admin:*******#cluster0.iyemf.mongodb.net/tinder-db?retryWrites=true&w=majority`
// middlewares
app.use(express.json())
app.use(Cors())
// db config
mongoose.connect(connection_url, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology:true,
})
// api endpoints
app.get('/', (req, res) => res.status(200).send("hello world"));
app.post('/tinder/cards', (req, res) => {
const dbCard = req.body;
Cards.create(dbCard, (err, data) => {
if (err) {
res.status(500).send(err)
} else {
res.status(201).send(data)
}
})
})
app.get("/tinder/cards", (req, res) => {
Cards.find((err, data) => {
if (err) {
res.status(500).send(err)
} else {
res.status(200).send(data)
}
});
});
// listener
app.listen(port, () => console.log(`listening on localehost: ${port}`));
You should also add the urlencoded middleware:
app.use(express.json());
app.use(express.urlencoded({
extended: true,
}));
How do I convert my app that is made with .pug to next app ? I have an app using .pug engine and I want to convert it into next.
This is the app.js but as I know next is different how do I do it? Because here my files are in views, and in views the files are in pages etc how do I do it? Is there any way or I have to code it all again?
const express = require('express');
const app = express();
const port = process.env.PORT || 3000;
const middleware = require('./middleware')
const path = require('path')
const bodyParser = require("body-parser")
const mongoose = require("./database");
const session = require("express-session");
const http = require('http');
const server = app.listen(port, () => console.log("Server listening on port " + port));
const io = require("socket.io")(server, { pingTimeout: 60000 });
app.set("view engine", "pug");
app.set("views", "views");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, "public")));
app.use(session({
secret: "#########",
resave: true,
saveUninitialized: false
}))
// Routes
const loginRoute = require('./routes/loginRoutes');
const registerRoute = require('./routes/registerRoutes');
const logoutRoute = require('./routes/logout');
const postRoute = require('./routes/postRoutes');
const profileRoute = require('./routes/profileRoutes');
const uploadRoute = require('./routes/uploadRoutes');
const searchRoute = require('./routes/searchRoutes');
const messagesRoute = require('./routes/messagesRoutes');
const notificationsRoute = require('./routes/notificationRoutes');
// Api routes
const postsApiRoute = require('./routes/api/posts');
const usersApiRoute = require('./routes/api/users');
const chatsApiRoute = require('./routes/api/chats');
const messagesApiRoute = require('./routes/api/messages');
const notificationsApiRoute = require('./routes/api/notifications');
app.use("/login", loginRoute);
app.use("/register", registerRoute);
app.use("/logout", logoutRoute);
app.use("/posts", middleware.requireLogin, postRoute);
app.use("/profile", middleware.requireLogin, profileRoute);
app.use("/uploads", uploadRoute);
app.use("/search", middleware.requireLogin, searchRoute);
app.use("/messages", middleware.requireLogin, messagesRoute);
app.use("/notifications", middleware.requireLogin, notificationsRoute);
app.use("/api/posts", postsApiRoute);
app.use("/api/users", usersApiRoute);
app.use("/api/chats", chatsApiRoute);
app.use("/api/messages", messagesApiRoute);
app.use("/api/notifications", notificationsApiRoute);
app.get("/", middleware.requireLogin, (req, res, next) => {
var payload = {
pageTitle: "Home",
userLoggedIn: req.session.user,
userLoggedInJs: JSON.stringify(req.session.user),
}
res.status(200).render("home", payload);
})
io.on("connection", socket => {
socket.on("setup", userData => {
socket.join(userData._id);
socket.emit("connected");
})
socket.on("join room", room => socket.join(room));
socket.on("typing", room => socket.in(room).emit("typing"));
socket.on("stop typing", room => socket.in(room).emit("stop typing"));
socket.on("notification received", room => socket.in(room).emit("notification received"));
socket.on("new message", newMessage => {
var chat = newMessage.chat;
if(!chat.users) return console.log("Chat.users not defined");
chat.users.forEach(user => {
if(user._id == newMessage.sender._id) return;
socket.in(user._id).emit("message received", newMessage);
})
});
})
If you don't want to refactor all your pug template engine pages to next.js pages, then you can make the pug pages coexist with the next.js. You can make the next.js the default route, and place next.js code after all pug page routes. And you also need to refactor app.get("/", middleware.requireLogin, (req, res, next) => {...} to make sure next.js is the default route.
To apply this rule, you need a custom next.js server.
sample code
const express = require('express');
const next = require('next');
const port = 3000;
const dev = process.env.NODE_ENV !== 'production'; // use default NodeJS environment variable to figure out dev mode
const app = next({dev, conf});
const handle = app.getRequestHandler();
const server = express();
// all your pug page routes should be declared before `server.get('*'`.
server.get('*', authMiddleware(false), (req, res) => {
// pass through everything to NextJS
return handle(req, res);
});
app.prepare().then(() => {
server.listen(port, (err) => {
if (err) throw err;
console.log('NextJS is ready on http://localhost:' + port);
});
}).catch(e => {
console.error(e.stack);
process.exit(1);
});
When I run heroku local, app working as expecting.
On production, it's not loading anything from Mlab (remote mongoDb)
Here is it
https://react-bulletin.herokuapp.com/
Just showing static react file.
here is my server file
require('dotenv').config();
// Express Stuff
const express = require('express');
const app = express();
const cors = require('cors')
const path = require('path')
// Mongo Wrapper
const mongoose = require('mongoose');
// Supporting Libraries
const bodyParser = require('body-parser');
// Globals
const dbUrl = process.env.MONGODB_URI
const port = process.env.PORT
mongoose.connect(dbUrl, {
useNewUrlParser: true,
useFindAndModify: false
});
app.use(cors())
app.use(bodyParser.json());
app.use('/', require('./Routes'));
if (process.env.NODE_ENV === 'production') {
// Serve any static files
app.use(express.static(path.join(__dirname, 'client/build')));
// Handle React routing, return all requests to React app
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
}
const PORT = process.env.PORT || 5000;
app.listen(port, () => {
console.log(`Running at http://localhost:${PORT}`);
I have no idea why is that.
Please any help.
PS
MONGODB_URI is added to heroku varibles.
System Information
Express: 4.16.4
NextJS: 8.0.3
React: 16.8.4
ReactDOM: 16.8.4
Goal
Serve the web application using SSL over HTTPS on localhost
What has been done
Created basic NextJS application using Create Next App
Generated a certificate and key using OpenSSL and moved it into the project directory
Added the Express dependency
Configured the app to use express inside server.js
Changed script to use the server.js inside package.json scripts.
server.js
const express = require('express');
const next = require('next');
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const port = 3000;
const https = require('https');
const fs = require('fs');
const httpsOptions = {
key: fs.readFileSync('./certificates/key.pem'),
cert: fs.readFileSync('./certificates/cert.pem')
};
app
.prepare()
.then(() => {
const server = express();
server.get('*', (req, res) => {
return handle(req, res);
});
server.listen(port, err => {
if (err) throw err;
console.log('> Ready on http://localhost: ' + port);
});
})
.catch(ex => {
console.error(ex.stack);
process.exit(1);
});
Extra Information
The app currently works when initialized using yarn dev. I have tried to serve the app over https using this answer but I was unable to figure out how to apply this to my current setup using NextJS.
I spent a lot of time researching the web how to apply this solution but have not yet found a way on how to make this work.
Any help is greatly appreciated.
You just need to use the createServer method of https module.
const { createServer } = require('https');
const { parse } = require('url');
const { readFileSync } = require('fs');
const next = require('next');
const port = 3000;
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const httpsOptions = {
key: readFileSync('./certificates/key.pem'),
cert: readFileSync('./certificates/cert.pem')
};
app.prepare()
.then(() => {
createServer(httpsOptions, (req, res) => {
const parsedUrl = parse(req.url, true);
handle(req, res, parsedUrl);
}).listen(port, err => {
if (err) throw err;
console.log(`> Ready on https://localhost:${port}`);
})
});
Other answer seemed to just drop express... Found a solution after some difficulty with both server code and certificate so hopefully can save someone else the trouble!
First of all, solid advice for creating localhost certificate here:
https://letsencrypt.org/docs/certificates-for-localhost/
Secondly, simple code that offers HTTP/HTTPS with next js and express:
const next = require('next');
const express = require('express');
const http = require('http');
const https = require('https');
const fs = require('fs');
const ports = {
http: 3080,
https: 3443
}
const dev = process.env.NODE_ENV !== 'production';
const app = next({ dev });
const handle = app.getRequestHandler();
const server = express();
const options = {
key: fs.readFileSync('localhost.key'),
cert: fs.readFileSync('localhost.crt'),
};
app.prepare().then(() => {
server.all('*', (req, res) => {
return handle(req, res)
});
http.createServer(server).listen(ports.http);
https.createServer(options, server).listen(ports.https);
});
It is worth noting that one could omit or redirect either port.
Below work for me very well for next server with https;
Using this official documentation of node js https module Creating HTTPS Server
const { createServer } = require('http')
const { parse } = require('url')
const next = require('next')
const { readFileSync } = require('fs');
const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()
const httpsOptions = {
pfx: readFileSync('./certificates/AMB.pfx'),
passphrase: 'Testabc$'
};
app.prepare().then(() => {
createServer(httpsOptions, (req, res) => {
const parsedUrl = parse(req.url, true)
const { pathname, query } = parsedUrl
if (pathname === '/login') {
app.render(req, res, '/login', query)
} else {
handle(req, res, parsedUrl)
}
}).listen(port, err => {
if (err) throw err
console.log(`> Ready on https://localhost:${port}`)
})
})
Our straightforward, switchable implementation:
const app = require('express')();
const https = require('https');
const http = require('http');
const next = require('next');
const fs = require('fs');
const path = require('path');
const HTTPS = true;
const server = HTTPS
? https.createServer(
{
key: fs.readFileSync(path.resolve(__dirname, './server.key')),
cert: fs.readFileSync(path.resolve(__dirname, './server.cert')),
},
app
)
: http.createServer({}, app);
const port = parseInt(process.env.PORT, 10) || 3000;
const dev = process.env.NODE_ENV !== 'production';
const nextApp = next({ dev });
const nextHandler = nextApp.getRequestHandler();
nextApp.prepare().then(() => {
app.get('/api/something', (req, res) => {
res.json({});
});
// ...
app.get('*', (req, res) => {
return nextHandler(req, res);
});
server.listen(port, (err) => {
if (err) throw err;
console.log(`> Ready on http${HTTPS ? 's' : ''}://localhost:${port}`);
});
});
I have a Mongo database set up on a Bitnami Lightsail MEAN stack instance that I am trying to connect to with an Angular/Node/Express application that I am building. I have followed the instructions on how to connect and create SSH Port Forwarding from my local machine (https://docs.bitnami.com/aws/infrastructure/mean/).
I am able access localhost:8888, which gives me access to RockMongo that was set up on the MEAN Lightsail instance with my Mongo database. That being said, I think the configuration for the connection to the server from my local machine is fine.
When I run node server and navigate to the URL (http://localhost:3000/api/numbers) for my api GET method, I am not receiving an error on connecting to the database. Instead, I get the following response, which is basically an empty array of data:
{"status":200,"data":[],"message":null}
Here is the code for my api.js file:
const express = require('express');
const router = express.Router();
const MongoClient = require('mongodb').MongoClient;
const ObjectID = require('mongodb').ObjectID;
// Connect
const connection = (closure) => {
return MongoClient.connect('mongodb://localhost:27017/sakDB', (err, db) => {
if (err) {
return console.log(err);
}
closure(db);
});
};
// Error handling
const sendError = (err, res) => {
response.status = 501;
response.message = typeof err == 'object' ? err.message : err;
res.status(501).json(response);
};
// Response handling
let response = {
status: 200,
data: [],
message: null
};
// Get numbers
router.get('/numbers', (req, res) => {
connection((db) => {
db.collection('numbers')
.find()
.toArray()
.then((numbers) => {
response.data = numbers;
res.json(response);
})
.catch((err) => {
sendError(err, res);
});
});
});
module.exports = router;
And the code for my router.js file:
const express = require('express');
const bodyParser = require('body-parser');
const path = require('path');
const http = require('http');
const app = express();
const api = require('./server/routes/api');
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(express.static(path.join(__dirname, 'dist')));
app.use('/api', api);
app.get('*', (req, res) => {
res.sendFile(path.join(__dirname, 'dist/index.html'));
});
const port = process.env.PORT || '3000';
app.set('port', port);
const server = http.createServer(app);
server.listen(port, () => console.log(`Running on localhost:${port}`));
I am beginning to think that this is some configuration issue with MongoDB on the MEAN Lightsail instance. If I try to run db.numbers.find() in MongoDB shell, I get the following error:
MongoDB server version: 3.4.7
> db.numbers.find()
Error: error: {
"ok" : 0,
"errmsg" : "not authorized on sakDB to execute command { find: \"numbers\", filter: {} }",
"code" : 13,
"codeName" : "Unauthorized"
}
I have to log in as a user mongo sakDB -u admin -p that I created to in order to find data on the collection.
When I try adding those credentials to the connection string mongodb://admin:PASSWORD#localhost:27017/sakDB, I receive a different authentication error:
name: 'MongoError',
message: 'Authentication failed.',
ok: 0,
errmsg: 'Authentication failed.',
code: 18,
codeName: 'AuthenticationFailed' }
It looks like this issue was related to Bitnami's server configuration with my Express application. It has been resolved.