Express server add ssl - node.js

I followed the angular server-side rendering tutorial and created an express server.
How can I add SSL support?
I found how to add SSL in server.js but I don't know how to add it in Typescript.
server.ts
import 'zone.js/dist/zone-node';
import 'reflect-metadata';
import { renderModuleFactory } from '#angular/platform-server';
import { enableProdMode } from '#angular/core';
import * as express from 'express';
import { join } from 'path';
import { readFileSync } from 'fs';
enableProdMode();
const app = express();
const PORT = process.env.PORT || 4000;
const DIST_FOLDER = join(process.cwd(), 'dist');
const template = readFileSync(join(DIST_FOLDER, 'browser', 'index.html')).toString();
const { AppServerModuleNgFactory, LAZY_MODULE_MAP } = require('./dist/server/main.bundle');
const { provideModuleMap } = require('#nguniversal/module-map-ngfactory-loader');
app.engine('html', (_, options, callback) => {
renderModuleFactory(AppServerModuleNgFactory, {
document: template,
url: options.req.url,
extraProviders: [
provideModuleMap(LAZY_MODULE_MAP)
]
}).then(html => {
callback(null, html);
});
});
app.set('view engine', 'html');
app.set('views', join(DIST_FOLDER, 'browser'));
app.get('*.*', express.static(join(DIST_FOLDER, 'browser')));
app.get('*', (req, res) => {
res.render(join(DIST_FOLDER, 'browser', 'index.html'), { req });
});
app.listen(PORT, () => {
console.log(`Node server listening on http://localhost:${PORT}`);
});
——————
I used a Reverse Proxy instead

import the fs and https module
import { readFileSync } from 'fs';
import * as https from 'https';
Now create an object to set the key and certificate paths.
const options = {
key: readFileSync('./ssl/privatekey.pem'),
cert: readFileSync('./ssl/certificate.pem'),
};
https.createServer(options, app).listen(PORT , function(){
console.log("Express server listening on port " + PORT);
});

Related

Socket.IO giving constant polling 404 error (Socket.IO new user)

Im using a Express server and trying to implement Socket.io for the first time, and I keep getting this whenever I open it:
GET /socket.io/?EIO=4&transport=polling&t=OKgNATB 404 0.526 ms - 149
GET /socket.io/?EIO=4&transport=polling&t=OKgNBww 404 0.332 ms - 149
GET /socket.io/?EIO=4&transport=polling&t=OKgNDOV 404 0.411 ms - 149
app.ts:
import express from 'express';
import morgan from 'morgan';
import favicon from 'serve-favicon';
import path from 'path';
import cors from 'cors';
import { errorManager } from './middlewares/errors_middleware.js';
import { ordersRouter } from './routers/OrdersRouter.js';
import { usersRouter } from './routers/UsersRouter.js';
import { createServer } from 'http';
import { Server } from 'socket.io';
export const app = express();
const httpServer = createServer(app);
const io = new Server(httpServer, {
cors: {
origin: '*',
},
});
io.on('connection', (socket) => {
console.log('HELLO');
});
app.use(favicon(path.join('.', 'public', 'favicon.ico')));
app.use(cors());
app.use(morgan('dev'));
app.use(express.json());
app.get('/', (_req, res, next) => {
res.send('H');
next();
});
Routers
app.use('/orders', ordersRouter);
app.use('/users', usersRouter);
app.use(errorManager);
index.ts:
import http from 'http';
import createDebug from 'debug';
import { app } from './app.js';
import { dbConnect } from './dbconnect/dbconnect.js';
const debug = createDebug('StoryLine:INDEX');
const port = 3300;
const server = http.createServer(app);
server.on('listening', () => {
const addr = server.address();
if (addr === null) return;
let bind: string;
if (typeof addr === 'string') {
bind = 'pipe ' + addr;
else {
bind =
addr.address === '::'
? `http://localhost:${addr?.port}`
: `port ${addr?.port}`;
}
debug(`SERVER: Listening on: ${bind}`);
});
server.on('error', (error: Error, response: http.ServerResponse) => {
response.write(error.message);
response.end();
});
dbConnect()
.then((mongoose) => {
debug(
'Database connection -> SUCCESSFUL: ',
mongoose.connection.db.databaseName
);
server.listen(port);
})
.catch((error) => {
debug('Database connection -> COULD NOT CONNECT');
server.emit(error);
});
I simply want to get a console.log telling me that a user is connecting. I have tried following the Socket.io docs for express but its not working for me.

WebSocket with angular universal

I'm trying to add websockets to a server that's using angular universal. As far as I can tell, express is consuming my request before it gets to my sockets, but I could be wrong about that.
I get this error in chrome:
WebSocket connection to 'ws://localhost:4200/socket' failed: Connection closed before receiving a handshake response
and I get this error in firefox:
Firefox can’t establish a connection to the server at ws://localhost:4200/socket.
when I run a separate nodejs server without the angular code, the websockets work fine.
Here is the relevant part of my server.ts
import 'zone.js/dist/zone-node'
import { ngExpressEngine } from '#nguniversal/express-engine'
import * as express from 'express'
import { join } from 'path'
import { AppServerModule } from './src/main.server'
import { APP_BASE_HREF } from '#angular/common'
import { existsSync } from 'fs'
import * as WebSocket from 'ws'
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express()
const distFolder = join(process.cwd(), 'dist/CAHClone/browser')
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index'
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}))
server.set('view engine', 'html')
server.set('views', distFolder)
server.use(express.json())
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}))
// All regular routes use the Universal engine
server.get('*', (req, res, next) => {
if (req.url === '/socket') return next() // leave '/socket' open for the websockets
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] })
})
return server
}
function run() {
const port = process.env.PORT || 4000
// Start up the Node server
const expressApp = app()
const server = expressApp.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`)
})
// Websockets
const wss = setupWebsockets(server)
}
function setupWebsockets(server) {
const wss = new WebSocket.Server({ server, path: '/socket' })
wss.on('connection', ws => {
console.log('Client connected.')
ws.send({message: 'Hi there!'})
})
wss.on('message', msg => {
console.log('Client said: ' + msg.toString())
})
return wss
}
declare const __non_webpack_require__: NodeRequire
const mainModule = __non_webpack_require__.main
const moduleFilename = mainModule && mainModule.filename || ''
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run()
}
export * from './src/main.server'
And here is a server.js file that works without angular related code
const express = require('express')
const WebSocket = require('ws')
const { join } = require('path')
const { existsSync } = require('fs')
// The Express app is exported so that it can be used by serverless Functions.
function app() {
const server = express()
server.use(express.json())
server.use('*', (req, res, next) => {
if (req.url === '/socket') return next()
res.end('Hello, world!')
})
return server
}
function setupWebsockets(server) {
const wss = new WebSocket.Server({ server, path: '/socket' })
console.log('set up websocket server');
wss.on('connection', ws => {
console.log('Client connected.');
ws.send('Hi there!')
})
wss.on('message', msg => {
console.log('Client said: ' + msg.toString());
})
}
function run() {
const port = process.env.PORT || 4000
const expressApp = app()
const server = expressApp.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`)
})
// Websockets
const wsServer = setupWebsockets(server)
}
run()
Could anyone help me understand what part of angular universal is breaking my websockets, and how to fix it?
I ran into this issue with the 'ws' module and passing in an express server. Try creating your server with the 'http' module and pass it into both express and 'ws'. I also recommend taking care of any authorization that you are going to do in the 'upgrade' event if necessary.
Did you solve the matter with dev:ssr ?
It is indeed working fine with serve:ssr but the only way I made it work with dev:ssr in local development is by using a proxy from ws://localhost:4200/ws to ws://localhost:4000
{
"/ws": {
"target": "ws://localhost:4000",
"secure": false,
"ws": true
}
}
Se my question here : Angular Universal (ssr-dev-server) Setting or getting the random port of the express app in dev:ssr

Error: ENOENT: no such file or directory, open 'dist/index.html'

So, I've been trying for days to get a angular universal app running but I keep getting this issue when I try to run the server like
npm run dev:ssr
I have set my server.ts file as in the below link
https://github.com/Angular-RU/angular-universal-starter/blob/master/server.ts
My server.ts file is as below
import 'zone.js/dist/zone-node';
import { ngExpressEngine } from '#nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '#angular/common';
import { existsSync } from 'fs';
// ssr DOM
const domino = require('domino');
const fs = require('fs');
const path = require('path');
// index from browser build!
const template = fs.readFileSync(path.join('.', 'dist', 'index.html')).toString();
// for mock global window by domino
const win = domino.createWindow(template);
// from server build
const files = fs.readdirSync(`${process.cwd()}/dist-server`);
// mock
global['window'] = win;
// not implemented property and functions
Object.defineProperty(win.document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
// mock documnet
global['document'] = win.document;
// othres mock
global['CSS'] = null;
// global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
global['Prism'] = null;
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express();
const distFolder = join(process.cwd(), 'dist');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// Example Express Rest API endpoints
// server.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
return server;
}
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
const moduleFilename = mainModule && mainModule.filename || '';
if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
run();
}
export * from './src/main.server';
my app.server.module.ts file:
import { NgModule } from '#angular/core';
import { ServerModule } from '#angular/platform-server';
import { AppModule } from './app.module';
import { AppComponent } from './app.component';
#NgModule({
imports: [
AppModule,
ServerModule,
],
bootstrap: [AppComponent],
})
export class AppServerModule {}
I am using Angular 9 and at a stage where I am thinking of dropping the idea of using angular universal at all. Seems it its way too unstable to be used at the moment.
Contents of dist folder:
Does anyone here have a solution to this?
You incorrectly set the distFolder variable. The distFolder from server.ts must point to the files containing the client side app, which is dist\YourProjectName\browser in your app. Note that this configured in angular.json file.
To correct your error, try changing the distFolder path in your server.ts
const distFolder = join(process.cwd(), 'dist','YourProjectName', 'browser');

Angular Universal page loading/refreshing issue

I have added Angular Universal in my project(upgraded to angular 8). Which is comparatively a big project. After solving all the window, jquery and localstorage issue I have successfully able to run the app. But the problem is, the server runs on localhost:4000. when I type localhost:4000 in browser nothing happens. But if I put localhost:4000/index.html, It starting to load fine and return to base localhost:4000. Then every angular route works fine. But if I try to refresh any page it doesn't load anything.
my server.ts
import 'zone.js/dist/zone-node';
// ssr DOM
const domino = require('domino');
const fs = require('fs');
const path = require('path');
const template = fs.readFileSync(path.join('dist/browser', 'index.html')).toString();
const win = domino.createWindow(template);
global['window'] = win;
Object.defineProperty(win.document.body.style, 'transform', {
value: () => {
return {
enumerable: true,
configurable: true,
};
},
});
// mock documnet
global['document'] = win.document;
// othres mock
global['CSS'] = null;
// global['XMLHttpRequest'] = require('xmlhttprequest').XMLHttpRequest;
global['Prism'] = null;
import { ngExpressEngine } from '#nguniversal/express-engine';
import * as express from 'express';
import { join } from 'path';
import { AppServerModule } from './src/main.server';
import { APP_BASE_HREF } from '#angular/common';
import { existsSync } from 'fs';
// The Express app is exported so that it can be used by serverless Functions.
export function app() {
const server = express();
const distFolder = join(process.cwd(), 'dist/browser');
const indexHtml = existsSync(join(distFolder, 'index.original.html')) ? 'index.original.html' : 'index';
// Our Universal express-engine (found # https://github.com/angular/universal/tree/master/modules/express-engine)
server.engine('html', ngExpressEngine({
bootstrap: AppServerModule,
}));
server.set('view engine', 'html');
server.set('views', distFolder);
// Example Express Rest API endpoints
// app.get('/api/**', (req, res) => { });
// Serve static files from /browser
server.get('*.*', express.static(distFolder, {
maxAge: '1y'
}));
// All regular routes use the Universal engine
server.get('*', (req, res) => {
res.render(indexHtml, { req, providers: [{ provide: APP_BASE_HREF, useValue: req.baseUrl }] });
});
return server;
}
function run() {
const port = process.env.PORT || 4000;
// Start up the Node server
const server = app();
server.listen(port, () => {
console.log(`Node Express server listening on http://localhost:${port}`);
});
}
// Webpack will replace 'require' with '__webpack_require__'
// '__non_webpack_require__' is a proxy to Node 'require'
// The below code is to ensure that the server is run only when not requiring the bundle.
declare const __non_webpack_require__: NodeRequire;
const mainModule = __non_webpack_require__.main;
if (mainModule && mainModule.filename === __filename) {
run();
}
export * from './src/main.server';
I think i need some change with this file to load correctly.

What's wrong with this ReactRouter.match() implementation?

I'm trying to serve up React from my server via express.
The error I'm getting, though, when I hit localhost:3000 is:
TypeError: (0 , _reactRouter.match) is not a function
at /Users/chris/code/affordance/app/server.js:20:3
Here's the server.js file that does that:
import path from 'path';
import { Server } from 'http';
import Express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import { match, RouterContext } from 'react-router';
import routes from './routes';
import NotFoundPage from './components/NotFoundPage';
// Initialize the express server, and tell it to use ejs
const app = new Express();
const server = new Server(app);
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
// Tell express where the static assets are
app.use(Express.static(path.join(__dirname, 'static')));
app.get('*', (req, res) => {
match(
{ routes, location: req.url },
(err, redirectLocation, renderProps) => {
if (err) {
return res.status(500).send(err.message);
}
if (redirectLocation) {
return res.redirect(302, redirectLocation.pathname + redirectLocation.search);
}
let markup;
if (renderProps) {
markup = renderToString(<RouterContext {...renderProps}/>);
} else {
markup = renderToString(<NotFoundPage/>);
res.status(404);
}
return res.render('index', { markup });
}
);
});
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || 'production';
server.listen(port, err => {
if (err) {
return console.error(err);
}
console.info(`Server running on http://localhost:${port} [${env}]`);
});
So as far as I can tell, I'm importing it the way I see it used elsewhere (for instance, here).
I'm missing something, and I don't know what to guess or think next. What am I doing wrong?
ps - react-router is at version 4.0.0, docs for match are here
Your code looks correct if you used react router prior to v4, but react-router v4 has breaking changes throughout the codebase, including the method for server rendering. In v4, there is a new component specifically for server rendering - StaticRouter.
Your code should looks something like this with v4:
import path from "path";
import { Server } from "http";
import Express from "express";
import React from "react";
import { renderToString } from "react-dom/server";
import { StaticRouter } from "react-router";
import App from "./app";
import NotFoundPage from "./components/NotFoundPage";
// Initialize the express server, and tell it to use ejs
const app = new Express();
const server = new Server(app);
app.set("view engine", "ejs");
app.set("views", path.join(__dirname, "views"));
// Tell express where the static assets are
app.use(Express.static(path.join(__dirname, "static")));
app.get("*", (req, res) => {
// This context object contains the results of the render
const context = {};
const html = renderToString(
<StaticRouter location={req.url} context={context}>
<App />
</StaticRouter>
);
res.status(200).send(html);
});
const port = process.env.PORT || 3000;
const env = process.env.NODE_ENV || "production";
server.listen(port, err => {
if (err) {
return console.error(err);
}
console.info(`Server running on http://localhost:${port} [${env}]`);
});
Here is a really nice annotated article by EbayTech showing how to set up an app with StaticRouter(for server) and BrowserRouter(for client)

Resources