I have 3 microservices in Spring:
Netflix Eureka
A Producer
A Consumer
And another microservice written in NodeJs with Eureka-js-client
node-microservice
Spring Eureka dashboard lists all of them
Until now everything looks OK, but the problem is when I try to read my node-microservice instance in eureka server. While I successfully find employee-producer instance in this way
List<ServiceInstance> instances=discoveryClient.getInstances("employee-producer");
ServiceInstance serviceInstance=instances.get(0);
I'm not able to find my node-microservice
List<ServiceInstance> instances=discoveryClient.getInstances("node-microservice");
ServiceInstance serviceInstance=instances.get(0);
From debug the result is
node-microservice
const Eureka = require('eureka-js-client').Eureka;
const express = require('express');
const server = express();
server.use(express.json());
server.use(function(req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
server.listen(3001);
server.get('/', function (req, res) {
res.send("CIaooo");
});
// example configuration
const client = new Eureka({
// application instance information
instance: {
app: 'node-microservice',
hostName: 'localhost',
ipAddr: '127.0.0.1',
port: {
'$': 3001,
'#enabled': 'true',
},
vipAddress: 'jq.test.something.com',
statusPageUrl: 'http://localhost:3001/info',
dataCenterInfo: {
'#class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo',
name: 'MyOwn',
}
},
eureka: {
// eureka server host / port
host: 'localhost',
port: 8761,
servicePath: '/eureka/apps/'
},
});
client.logger.level('debug');
client.start(function(error){
console.log(error || 'complete')});
Other strange thing is that from spring debug I can list services, where also node-microservice is listed
What's wrong with my code?
The problem is that in the instance object I didn't write instanceId (wasn't mentioned anywhere). I found this solution crawling the code and than in another project where there was also this field
instance: {
app: 'node-microservice',
instanceId: 'nodemicroservice',
hostName: 'localhost',
ipAddr: '127.0.0.1',
port: {
'$': 3001,
'#enabled': 'true',
},
vipAddress: 'nodemicroservice',
statusPageUrl: 'http://localhost:3001/info',
dataCenterInfo: {
'#class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo',
name: 'MyOwn',
},
registerWithEureka: true,
fetchRegistry: true
},
Related
I'm trying to run NodeBB through a node.js reverse proxy (https://docs.nodebb.org/configuring/proxies/node/)
I've followed every tutorial, hint/tip I can but am still experiencing issues with websocket connections to my NodeBB server, causing session problems, can't log in etc.
My setup is as follows:
App 1 - http://www.mywebsite.co.uk/
Node.js & Express
Routing for API & frontend website
Nothing out of the ordinary
Full code snippet at bottom of post
I am using the 'http-proxy' npm module to proxy anyone who loads http://mywebsite.co.uk/forum to http://www.myforum.co.uk/forum
This part is working, assets load as expected. However, there is a part of NodeBB which uses websockets to poll the forum for functionality purposes, user sessions. This part is not proxying correctly, or at least the NodeBB response is not correct and therefore giving me lots of errors:
"You are accessing the forum from an unknown origin. This will likely
result in websockets failing to connect. To fix this, set the "url"
value in config.json to the URL at which you access the site. For
more information, see this FAQ topic:
https://community.nodebb.org/topic/13388"
Also:
"Looks like your connection to NodeBB was lost, please wait while we
try to reconnect."
And, in the network panel, lots of 'pending' requests which eventually fail with an empty response from NodeBB.
http://mywebsite.co.uk/forum/socket.io/?EIO=3&transport=polling&t=MgJQSMk
App 2 - http://www.myforum.co.uk/forum
This app is a basic NodeBB installation running, with one plugin - (https://github.com/julianlam/nodebb-plugin-session-sharing)
The config JSON file looks like this (note the URL is my frontend app's URL as per the instructions when proxying.
{
"url": "http://www.mywebsite.co.uk/forum",
"secret": "secret",
"database": "postgres",
"port": "4567",
"postgres": {
"host": "HOST",
"port": "PORT",
"password": "PASSWORD",
"database": "DATABASE"
}
}
App 1 code:
// app
const express = require("express");
const app = express();
app.use(require('cookie-parser')());
app.use(require('body-parser').urlencoded({ extended: true }));
app.use(require('express-session')({ secret: 'secret', resave: true, saveUninitialized: true }));
//
app.use((req, res, next) => {
res.setHeader("Access-Control-Allow-Origin", "*");
res.setHeader(
"Access-Control-Allow-Methods",
"OPTIONS, GET, POST, PUT, PATCH, DELETE"
);
res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization");
next();
});
// serve the content
app.use(express.static("dist"));
// Frontend
app.set('view engine', 'pug');
// serve out the api
// app.use ...
// Server set up
const httpProxy = require('http-proxy');
const HttpProxyRules = require('http-proxy-rules');
// Forum urls
let rules = {
rules: {
'/forum': 'http://www.myforum.co.uk/forum',
'/forum/*': 'http://www.myforum.co.uk/forum',
},
};
const proxyRules = new HttpProxyRules(rules);
const proxy = httpProxy.createProxy();
app.use(function (req, res, next) {
try {
if (req.url.includes("socket.io") === true) {
// console.log("SOCKET.IO", req.url)
return proxy.web(req, res, {
target: 'wss://www.myforum.co.uk',
ws: true,
changeOrigin: true
}, function (e) {
// console.log('PROXY ERR', e)
// next();
});
} else {
var target = proxyRules.match(req);
if (target) {
// console.log("TARGET", target, req.url)
return proxy.web(req, res, {
target: target,
changeOrigin: true
}, function (e) {
// console.log('PROXY ERR', e)
});
} else {
next();
}
}
} catch (e) {
// res.sendStatus(500);
res.json({ error: e });
}
});
// Frontend routes
// app.use ...
// HTTP
const http = require('http');
// Create server
mainserver = http.createServer(app);
const PORT = process.env.PORT || 3000;
mainserver.listen(PORT);
mainserver.on('listening', onListening);
mainserver.on('error', function (error, req, res) {
let json;
console.log('proxy error', error);
if (!res.headersSent) {
res.writeHead(500, { 'content-type': 'application/json' });
}
json = { error: 'proxy_error', reason: error.message };
res.end(JSON.stringify(json));
});
function onListening() {
console.log(`Listening on :${PORT}`);
}
To resolve this, I changed the Proxy module I was using. It uses less code to implement and works with websockets. I think the NodeBB Node.js proxy documentation is out of date so I'll be updating with the new method I found.
Working code is as follows:
/**
* Proxy forum
*/
const proxy = require('http-proxy-middleware');
// Forum Proxy
app.use(
'/forum',
proxy({
target: 'http://www.myforum.co.uk/forum',
changeOrigin: true,
ws: true,
})
);
Another potential GOTCHA here is that this Prixy setup needs to be declared ABOVE the 'body-parser' module (if it's being used). The wrong order will prevent post requests from being proxied.
I'm new to Node and I want my website, dacio.app, working with subdomains for my college projects using vhost.
However, I need to have it secured due to the requirement for .app domains, so I'm using greenlock-express to automate it.
Don't be frontin', yo! TLS SNI 'giphy.dacio.app' does not match 'Host:
potatoes.dacio.app'
I've tried using the vhost example in the repo, but it doesn't look like server-static supports express apps.
Any tips on how to get this working? I keep hearing about reverse proxies, but I'm not sure if it's worth the effort as I don't even know if it would work - would it help?
server.js
#!/usr/bin/env node
'use strict';
// DEPENDENCIES
const express = require('express');
const vhost = require('vhost');
const path = require('path');
const glx = require('greenlock-express');
// MIDDLEWARE
const app = express();
const giphyApp = require('../giphy-search');
const potatoesApp = require('../rotten-potatoes');
const portfolioApp = require('../dacio.app');
// ROUTES
app.use(vhost('giphy.dacio.app', giphyApp));
app.use(vhost('potatoes.dacio.app', potatoesApp));
app.use(portfolioApp);
// GREENLOCK for HTTPS
glx.create({
version: 'draft-11',
server: 'https://acme-v02.api.letsencrypt.org/directory',
email: 'dacioromero#gmail.com',
agreeTos: true,
approveDomains: [ 'dacio.app', 'giphy.dacio.app', 'potatoes.dacio.app' ],
configDir: '~/.config/acme/',
app: app,
communityMember: false
}).listen(80, 443);
I've switched to using redbird which seems to accomplish everything I was hoping to do.
const path = require('path')
const proxy = require('redbird')({
port: 80,
letsencrypt: {
path: path.join(__dirname, '/certs'),
port: 9999
},
ssl: {
http2: true,
port: 443
}
});
proxy.register('dacio.app', 'http://localhost:8080', {
ssl: {
letsencrypt: {
email: 'dacioromero#gmail.com',
production: true,
}
}
});
proxy.register('giphy.dacio.app', 'http://localhost:8081', {
ssl: {
letsencrypt: {
email: 'dacioromero#gmail.com',
production: true
}
}
})
proxy.register('potatoes.dacio.app', 'http://localhost:8082', {
ssl: {
letsencrypt: {
email: 'dacioromero#gmail.com',
production: true
}
}
});
What I want to achieve is:
registering a node.js service in my eureka-server in heroku.
So far i can register a regular eureka-client in my eureka-server in heroku, without problems. But i am getting really confused with the configuration when try with node.js service...
I thought eureka-js-client was the solution, no success so far...
Code below.
const express = require('express');
const path = require('path');
const port = process.env.PORT || 3090;
const app = express();
app.use(express.static(__dirname));
const bodyParser = require('body-parser');
app.use(bodyParser.urlencoded({extended: false}));
app.use(bodyParser.json());
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'index.html'))
});
const Eureka = require('eureka-js-client').Eureka;
const eureka = new Eureka({
instance: {
app: 'sheila',
hostName: 'localhost',
ipAddr: '127.0.0.1',
statusPageUrl: 'http://localhost:5000',
healthCheckUrl: 'http://localhost:5000/health',
port: {
'$': 5000,
'#enabled': 'true',
},
vipAddress: 'myvip',
dataCenterInfo: {
'#Class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo',
name: 'MyOwn',
},
},
eureka: {
host: 'localhost',
port: 8761,
servicePath: '/eureka/apps/',
},
});
eureka.logger.level('debug');
eureka.start(function(error){
console.log(error || 'complete');
});
// ------------------ Server Config --------------------------------------------
var server = app.listen(5000, function () {
var port = server.address().port;
console.log('Listening at %s', port);
});
First i've tried locally after running docker run -it -p 8761:8761 springcloud/eureka on my docker console. But i get this error:
Problem making eureka request { [Error: connect ECONNREFUSED 127.0.0.1:8761]
code: 'ECONNREFUSED',
errno: 'ECONNREFUSED',
syscall: 'connect',
address: '127.0.0.1',
port: 8761 }
if i run it as it is from a heroku service, It does not execute :( :(
I also tried by substituting the host for the url of my heroku eureka server, but then i get 401 or 404 errors. The eureka server requires a password which i added in my heroku client js .
Any ideas?
You need to include an instanceId which should be a unique identifier of this instance.
const eureka = new Eureka({
instance: {
instanceId:'sheila',
app: 'sheila',
hostName: 'localhost',
ipAddr: '127.0.0.1',
statusPageUrl: 'http://localhost:5000',
healthCheckUrl: 'http://localhost:5000/health',
port: {
'$': 5000,
'#enabled': 'true',
},
vipAddress: 'myvip',
dataCenterInfo: {
'#Class': 'com.netflix.appinfo.InstanceInfo$DefaultDataCenterInfo',
name: 'MyOwn',
},
},
eureka: {
host: 'localhost',
port: 8761,
servicePath: '/eureka/apps/',
},
});
I'm trying to access a remote url and just output it, this works:
app.get('/', function (req, res) {
http.get({
hostname: 'localhost',
port: 80,
path: '/',
agent: false // create a new agent just for this one request
}, (response) => {
console.log('foo');
});
});
but when I do:
app.get('/', function (req, res) {
http.get({
hostname: 'localhost',
port: 80,
path: '/',
agent: false // create a new agent just for this one request
}, (response) => {
console.log(response);
});
});
I get a Unable to load the webpage because the server sent no data. I also tried res.send(response)
I'm not sure about my settings, but if I write localhost:80, I get the page I'm trying to log
Turns out, the server is breaking because I didn't output any data. I needed to something like
res.render();
I am trying to host api and web servers on the same node code stack. I have used labels in order to apply configurations independently to each server but only one server works. Below is the code:
var hapi = require('hapi');
// server definition
var server = new hapi.Server();
var runningPort = process.env.PORT || 3000;
// setting up connection
server.connection({
host: '0.0.0.0',
port: runningPort,
labels: ['api']
});
server.connection({
host: '0.0.0.0',
port: runningPort,
labels: ['web']
});
var webServer = server.select('web');
var apiServer = server.select('api');
// registering view engine
webServer.views({
engines: { html: require('handlebars') },
relativeTo: __dirname,
path: './views',
layoutPath: './views/layout',
layout: 'default',
partialsPath: './views/partials'
});
// registering hapi auth cookie and application authentication
webServer.register(
{
register: require('hapi-auth-cookie')
},
function (err) {
if (err) {
throw err;
}
var cache = webServer.cache({ segment: 'sessions', expiresIn: 3 * 24 * 60 * 60 * 1000 });
webServer.app.cache = cache;
webServer.auth.strategy('session', 'cookie', true, {
password: 'secret',
cookie: 'sid-example',
redirectTo: '/account/login',
isSecure: false
});
});
// registrations for api server
apiServer.register(
{
register: require('lout')
},
function (err) {
if (err) {
throw err;
}
});
apiServer.register(require('hapi-auth-bearer-token'), function (err) {
apiServer.auth.strategy('simple', 'bearer-access-token', {
allowQueryToken: true, // optional, true by default
allowMultipleHeaders: false, // optional, false by default
accessTokenName: 'access_token', // optional, 'access_token' by default
validateFunc: function( token, callback ) {
// For convenience, the request object can be accessed
// from `this` within validateFunc.
var request = this;
// Use a real strategy here,
// comparing with a token from your database for example
if(token === "1234"){
//## user object to be looked up here
callback(null, true, { token: token })
} else {
callback(null, false, { token: token })
}
}
});
});
//To do something to request before they passed on to routes
apiServer.ext('onRequest', function (request, reply) {
//## we can get user object here off of the authToken
utils.log('info', 'apiCall', {method: request.method, path: request.path})
return reply.continue();
});
// register routes
webServer.route(webRoutes);
apiServer.route(apiRoutes);
server.start(function () {
console.log('Web servers running at: ', 'localhost:' + runningPort);
console.log('Api server running at: ', 'localhost:' + runningPort);
});
Currently only api routes work.
As mentioned by the commenters, you can't create 2 connections to the same port on the same network interface. This goes all the way back to the listen syscall giving a EADDRINUSE error if two sockets try to listen on the same port.
Creating two connections on separate ports or separate network interfaces is perfectly ok though:
server.connection({
host: '127.0.0.1',
port: 4000,
labels: ['api']
});
server.connection({
host: '127.0.0.1',
port: 4001,
labels: ['web']
});
As Matt already said, you can't run different connections on the same port. Make sure to apply different ports, like
server.connection({
host: 'localhost',
port: process.env.PORT || port
});
server.connection({
host: 'localhost',
port: process.env.PORT + 1 || port + 1
});
If you want to read more on running an API and your web server within the same hapi project, you might scan through those tutorials:
https://futurestud.io/tutorials/hapi-how-to-run-separate-frontend-and-backend-servers-within-one-project
https://futurestud.io/tutorials/hapi-how-to-use-server-labels
Hope that helps!