I'm trying to get node and swagger to work with nginx dynamically
server_name ~^backend(?<PORTSERVER>[^.]+)\.domain\.com$;
location /swagger
{
proxy_pass http://127.0.0.1:$PORTSERVER/swagger/;
}
location /api
{
proxy_pass http://127.0.0.1:$PORTSERVER/api;
}
this is an example of virtual host the PORTSERVER variable is taking from gitlab-ci it takes id number of merge request + 2000
when i put the port directly in place of $PORTSEVER every thing is working swagger and api
any advice is appreciated thank you
this is index.js file
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
require("reflect-metadata");
const typeorm_1 = require("typeorm");
const express = require("express");
// var router = express.Router();
const fileUpload = require("express-fileupload");
const bodyParser = require("body-parser");
const routes_1 = require("./routes");
const cors = require("cors");
const typeorm_pagination_1 = require("typeorm-pagination");
const swaggerUi = require('swagger-ui-express');
const swaggerDocument = require('../../swagger.json');
var path = require('path');
typeorm_1.createConnection()
.then((connection) => __awaiter(void 0, void 0, void 0, function* () {
// create express app
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded());
app.use(fileUpload());
app.use(express.static(path.join(__dirname, '..', 'public')));
console.log(path.join(__dirname, '..', 'public'));
// register express routes from defined application routes
routes_1.Routes.forEach((route) => {
app[route.method]('/api' + route.route, (req, res, next) => {
const result = new route.controller()[route.action](req, res, next);
res.header('Access-Control-Allow-Origin', '*');
if (result instanceof Promise) {
result.then((result) => (result !== null && result !== undefined ? res.send(result) : undefined));
}
else if (result !== null && result !== undefined) {
res.json(result);
}
});
});
// setup express app here
// ...
app.use('/swagger', swaggerUi.serve, swaggerUi.setup(swaggerDocument));
app.use(express.json());
app.use(cors());
app.use(typeorm_pagination_1.pagination); // Register the pagination middleware
// start express server
// app.listen(process.env.SERVER_Port);
app.listen(process.env.PORTSERVER);
console.log('Express server has started on port ' + process.env.PORTSERVER);
}))
.catch((error) => console.log(error));
//# sourceMappingURL=index.js.map
The key is his sentence is "when i put the port directly in place of $PORTSEVER every thing is working swagger and api"
Based on the description you gave, I think that gitlabci is miss generating the port number, or miss understanding the syntax.. Both gitlabci and nginx uses $VAR syntax.. Can be a miss interpretation of the 1st line regex too..
Also, I think you need to check the content of process.env.PORTSERVERa used in the js file.. It can have different port than nginx..
For this, I would approach the issue by preventing the the job from restarting nginx to not cause down time for other vhosts.. Deploy a broken config then from the server I run nginx -t and/or diff -u a working config and a broken one..
The 1st source of truth would be nginx -t and nginx logs.. If, ever, nginx manage the starts, the HTTP code it's returning can reveal more paths to pursuit.
One thing you forgot to share is the content of your gitlabci YML.. That can help identify the issue too.
Related
This question already has an answer here:
NodeJS callback with null as first argument
(1 answer)
Closed 9 months ago.
This is a code I found in the internet using Express and CORS:
const express = require('express');
const app = express();
const cors = require('cors');
var corsOptionsDelegate = async (req, callback) => {
var corsOptions = { origin: false };
try {
...
corsOptions.origin = true;
} catch (err) {
console.log(err);
}
callback(null, corsOptions)
}
app.use(cors(corsOptionsDelegate));
I don't know how this function callback(null, corsOptions) process in this code.
This is just a standard callback design pattern. Here's an article you can read but also you should learn more about what design patterns are and how Node.js works. This is a very basic question you're asking here.
You actually do not need any function callback for simple servers.
There is a much simpler way.
const whiteList = [ "https://myRealBackendUrl-1", "https://myRealBackendUrl-2" ];
// you can also pass a string here instead here instead of array
const corsOptions = {
credentials: true,
origin: process.env.NODE_ENV !== production ? "http://localhost:3000" : whiteList
// if you are in a dev environment, you probably want something like localhost
// if you are in a production environment, for example heroku then your backend
// url will be something like http://example.herokuapp.com
// in that case `const whiteList = [ "http://example.herokuapp.com" ];`
};
app.use(cors(corsOptions));
The above code should be enough for the normal use case.
As for the callback function, it is if you want to run some function of your own.
var corsOptionsDelegate = async (req, callback) => {
var corsOptions = { origin: false };
try {
// you can do some dynamic check here
// For example: check database for some conditions then allow access
if( myDatabaseSays == true ) corsOptions.origin = true;
else corsOptions.origin = false;
} catch (err) {
console.log(err);
// corsOptions.origin = false;
}
callback(null, corsOptions) // chain it
}
Anyway read the docs properly for more info
[1]: https://expressjs.com/en/resources/middleware/cors.html
I have been closely trying to follow this Vue SSR guide and in that example the author has placed his Express routes within a file called server.js. Simply for organisation purposes, I wish to keep my Express routes in a router.express.js file within my src/router folder instead of in the root file of server.js.
So this is a cutdown version of my router.express.js file:
const vueServerRenderer = require('vue-server-renderer');
const setupDevServer = require('../../build/setup-dev-server'); //webpack dev config
const express = require('express');
const app = express();
const router = express.Router();
const createRenderer = (serverBundle) =>
vueServerRenderer.createBundleRenderer(serverBundle, {
runInNewContext: false,
template: fs.readFileSync(path.resolve(__dirname, '../index.html'), 'utf-8')
});
let renderer;
if (process.env.NODE_ENV === 'development') {
setupDevServer(app, (serverBundle) => {
renderer = createRenderer(serverBundle);
});
} else {
renderer = createRenderer(require('../../dist/vue-ssr-server-bundle.json'));
}
router.get('/', async function (req, res) {
const context = {
url: req.params['0'] || '/'
};
let html;
try {
html = await renderer.renderToString(context);
} catch (error) {
if (error.code === 404) {
return res.status(404).send('404 | Page Not Found');
}
return res.status(500).send('500 | Internal Server Error');
}
res.end(html);
});
module.exports = router;
The problem is that I also need the vue-server-renderer code to be in the server.js file. I would then make the app require the router.express.js file so the Express routes work like this:
const vueServerRenderer = require('vue-server-renderer');
const setupDevServer = require('../../build/setup-dev-server'); //webpack dev config
const app = express();
const createRenderer = (serverBundle) =>
vueServerRenderer.createBundleRenderer(serverBundle, {
runInNewContext: false,
template: fs.readFileSync(path.resolve(__dirname, '../index.html'), 'utf-8')
});
let renderer;
if (process.env.NODE_ENV === 'development') {
setupDevServer(app, (serverBundle) => {
renderer = createRenderer(serverBundle);
});
} else {
renderer = createRenderer(require('../../dist/vue-ssr-server-bundle.json'));
}
app.use(require('./router/express.router.js'));
Whenever I do this, I get a Webpack error stating that
WebpackOptionsValidationError: Invalid configuration object. Webpack
has been initialised using a configuration object that does not match
the API schema.
- configuration.entry'app' should be a string.
If I remove the vue-server-renderer code from server.js then it runs fine. But the reason for having that code within server.js is so that the development environment works properly. Basically if the code is not in server.js then I cannot use hot-reloading or anything.
If I get rid of router.express.js and put all that code in server.js including the routes, then it all works perfectly including my development environment.
Why can I not (or rather how can I) keep my Express routes in a separate file and still have the vue-server-renderer stuff work?
Update: setup-dev-server.js file:
const setupDevServer = (app, onServerBundleReady) => {
const webpack = require('webpack');
const MFS = require('memory-fs');
const path = require('path');
const clientConfig = require('./webpack.client.config');
const serverConfig = require('./webpack.ssr.config');
// additional client entry for hot reload
clientConfig.entry.app = ['webpack-hot-middleware/client', clientConfig.entry.app];
const clientCompiler = webpack(clientConfig);
// setup dev middleware
app.use(require('webpack-dev-middleware')(clientCompiler, {
publicPath: clientConfig.output.publicPath,
serverSideRender: true,
logLevel: 'silent',
}));
// setup hot middleware
app.use(require('webpack-hot-middleware')(clientCompiler));
// watch src files and rebuild SSR bundle
global.console.log('Building SSR bundle...');
const serverCompiler = webpack(serverConfig);
const mfs = new MFS();
serverCompiler.outputFileSystem = mfs;
serverCompiler.watch({}, (error, stats) => {
if (error) throw error;
global.console.log(
`${stats.toString({
colors: true,
modules: false,
children: false,
chunks: false,
chunkModules: false,
})}\n\n`
);
if (stats.hasErrors()) {
console.error(stats.compilation.errors);
throw new Error(stats.compilation.errors);
}
// read bundle generated by vue-ssr-webpack-plugin
const bundle = JSON.parse(
mfs.readFileSync(path.join(clientConfig.output.path, 'vue-ssr-server-bundle.json'), 'utf-8')
);
onServerBundleReady(bundle);
});
};
module.exports = setupDevServer;
1) Inside of your 'router.express.js' file write: module.exports = router; at the bottom of the file.
2) Inside of your 'server.js' file write: const router = require('./router/express.router.js');
at the top of the file.
3) And now where you used to have app.use(require('./router/express.router.js'));
replace that with app.use(router);
4) At the top of 'server.js' write const vueSsrBundle = require('../../dist/vue-ssr-server-bundle.json')
5) Lastly replace renderer = createRenderer(require('../../dist/vue-ssr-server-bundle.json')
With renderer = createRenderer(vueSsrBundle)
EDIT the issue you are facing is on this line And probably related to the file 'app.js' or 'client-entry-js'
I'm doing a test with Nodejs to increment a global counter, according to the scripts below. Everything works, except that Chrome executes two sequential requests when I refresh it, which causes the counter to increment twice as well (see the image). In Postman and Firefox works fine and only one request occurs on refresh. I've done the tests running the app on Linux and Windows and the problem with Chrome holds. Anyone have any idea what might be happening?
server.js
const http = require('http');
const express = require('express');
const app = express();
const rotas = require("./route-test")(app);
const port = 3000;
const server = app.listen(process.env.PORT || port, function(){
console.log('App listening port: ', port);
});
route-test.js
const myGlobalVars = require("./global-vars");
module.exports = (app) => {
app.use('/', (req, res) => {
res.end('Counter in: ' + myGlobalVars.counter);
});
app.use(function(req, res, next){
//console.log(req.originalUrl);
});
}
global-vars.js
let myCounter = 0;
const _myVars = Object.create(Object.prototype, {
dateInit: {
writable: false,
configurable: false,
value: new Date()
},
counter: {
configurable: false,
get: function() { return myCounter++ },
set: function(_val) {
myCounter = _val;
}
}
});
module.exports = _myVars;
I check all 3 files... so in FireFox and Google Canary(developers version) we have only 1 request(we got 1 request and we increment only once myGlobalVars.counter ). in simple Google Chrome version we have 2 request. one of them is request for favicon.ico. so we just need to add condition to ignore favicon.ico request and dont increment twice our myGlobalVars.counter value...
in route-test.js
const myGlobalVars = require("./global-vars");
module.exports = (app) => {
app.use('/', (req, res) => {
// instead of this code res.end('Counter in: ' + myGlobalVars.counter);
// add this condition
if (req.url === '/') {
res.end( `\n\n\nCounter in: ${myGlobalVars.counter}` );
}
});
}
I think it's the request that the browser makes to the server to get /favicon.ico resource.
You might have faced this bug :
https://bugs.chromium.org/p/chromium/issues/detail?id=64810
Today, it should be fixed in Chrome, but you can still reproduce it in Chromium instrumented by puppeteer for example.
Why does Nuxt call the server for so many times on a single route/ page?
Below is the example I tested from their express-template:
import express from 'express'
import { Nuxt, Builder } from 'nuxt'
import api from './api'
const app = express()
const host = process.env.HOST || '127.0.0.1'
const port = process.env.PORT || 3000
app.set('port', port)
app.use(function(req, res, next) {
console.log(res.headersSent) // <-- pay attention here
next()
})
// Import API Routes
app.use('/api', api)
// Import and Set Nuxt.js options
let config = require('../nuxt.config.js')
config.dev = !(process.env.NODE_ENV === 'production')
// Init Nuxt.js
const nuxt = new Nuxt(config)
// Build only in dev mode
if (config.dev) {
const builder = new Builder(nuxt)
builder.build()
}
// Give nuxt middleware to express
app.use(nuxt.render)
// Listen the server
app.listen(port, host)
console.log('Server listening on ' + host + ':' + port) // eslint-disable-line no-console
This route/page/index.vue will call the api/users:
import axios from '~/plugins/axios'
export default {
async asyncData () {
let { data } = await axios.get('/api/users')
return { users: data }
},
head () {
return {
title: 'Users'
}
}
}
I added a console.log in plugins/axios.js:
import * as axios from 'axios'
let options = {}
// The server-side needs a full url to works
if (process.server) {
options.baseURL = `http://${process.env.HOST || 'localhost'}:${process.env.PORT || 3000}`
console.log('express:' + options.baseURL)
}
export default axios.create(options)
When I run the app and access it on my browser at http://127.0.0.1:3000/:
In my terminal I get:
false
express:http://localhost:3000
false
false
false
false
false
false
false
false
As you can see that it has called api/users 8 times more after the first call.
Is it a bug in Nuxt?
If I removed app.use(nuxt.render) from server/index.js:
// Give nuxt middleware to express
// app.use(nuxt.render)
And I access it at http://127.0.0.1:3000/ or http://127.0.0.1:3000/api/users, I get:
false
Just one call which is correct.
So, what is going on with Nuxt?
It's not a bug. Express is executing your middleware. In this case, they are http requests for client assets like app.js, logo.png etc. Change your middleware code like below and check the console.
app.use(function(req, res, next) {
console.log(req.url) // Change this line
next()
})
All,
I am trying to create a simple proxy which forwards all requests verbatum to another server. To do this I'm using the "http-proxy" npm. I am trying to go from local to a cloud server. At first when I setup the http-proxy I saw an error "unable to verify the first certificate". After some research online I found it's probably related to the fact that I have a self-signed certificate. Because it's self-signed it's not in the certificate store and so can't be validated. But, beacause I don't need this during development, I added "secure: false" to ignore certificate verification. I know that's unsafe from production, but I'm just trying to get around this for now. This update actually got around this error.
Now, I am getting another error "UNABLE_TO_VERIFY_LEAF_SIGNATURE".
Can any one help me figure out how to get rid of this error? I've tried adding this:
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
But that still shows the error. I see the error in the event emitted by the http-proxy (See code below for this event). If I drill down itno the 'proxyRes' I can see this error in the proxyRes -> connection -> authorizationError -> UNABLE_TO_VERIFY_LEAF_SIGNATURE
Here is my code below:
'use strict'
require('dotenv').config({silent: true})
var util = require('util');
const loggerFactory = require('./utils/logger')
const express = require('express')
const defaultRouter = require('./routes/default')
var logger = loggerFactory.consoleLogger
const proxy = require('http-proxy');
module.exports = (config) => {
const app = express()
// app.use(loggerFactory.requestLogger())
app.set('json spaces', 2)
app.set('port', config.express.port)
app.use('', defaultRouter)
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
var apiProxy = proxy.createProxyServer({});
var proxyUrl = process.env.HOMEINSPECTIONSERVER_URL;
app.use((req,res,next) => {
apiProxy.web(req, res,
{
target: proxyUrl,
secure: false,
}
);
apiProxy.on('error', function(e) {
logger.error("Error during proxy call!")
logger.error("This is the error : " + e)
next('route')
});
apiProxy.on('proxyReq', function(proxyReq, req, res, options) {
logger.info("---REQUEST---")
console.log("---REQUEST---")
// logger.info(util.inspect(proxyReq))
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
});
apiProxy.on('proxyRes', function (proxyRes, req, res) {
// logger.info("---RESPONSE---")
// logger.info(util.inspect(proxyRes))
// logger.info("---RESPONSEEND---")
logger.info('RAW Response from the target',
JSON.stringify(proxyRes.headers, true, 2));
});
apiProxy.on('open', function (proxySocket) {
proxySocket.on('data', hybiParseAndLogMessage);
});
apiProxy.on('close', function (res, socket, head) {
console.log('Client disconnected');
});
apiProxy.on('start', function (req, res, target) {
// console.log('Started Request!');
});
})
app.use((req, res) => {
// logger.info('starting request...')
res.json(res.locals.standardResponse)
})
app.use((err, req, res, next) => {
var statusCode = 500
if (res.locals.standardResponse) {
res.locals.standardResponse.error = err
statusCode = err.statusCode || 600
logger.error(err)
res.status(statusCode).json(res.locals.standardResponse)
}
if (err.error !== undefined && err.error.httpStatus !== undefined) {
statusCode = err.error.httpStatus
} else {
statusCode = err.statusCode || 600
}
logger.error(err)
res.status(statusCode).json(res.body)
})
return app
}
I had the same problem using http-proxy-middleware the problem is solved by adding secure: false like this
const {createProxyMiddleware} = require('http-proxy-middleware');
app.use('/firmware-images/:firmwareImageId/files/:fileId/download', createProxyMiddleware({ target: `${FILES_URL}`, changeOrigin: true, secure: false }));
I know is not the same package, but it is the same problem, so I hope it helps someone.
For any one also having this problem above. I solved it by using the npm package called express-http-proxy. You can get it here:
enter link description here
So my code now looks like this:
'use strict'
require('dotenv').config({silent: true})
const loggerFactory = require('./utils/logger')
const express = require('express')
const defaultRouter = require('./routes/default')
var logger = loggerFactory.consoleLogger
module.exports = (config) => {
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
const app = express()
app.set('json spaces', 2)
app.set('port', config.express.port)
app.use('', defaultRouter)
var proxy = require('express-http-proxy');
app.use(proxy(process.env.HOMEINSPECTIONSERVER_URL))
return app
}
Note the important piece of code here:
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = '0'
Hope that helps anyone who is stuck!