I have a REST API server running at https://localhost:7001. This one uses a JKS keystore for configuring https.
A combination of gulp + browser-sync + proxy-middleware that spins up a server serving static content at https://localhost:3000. All requests to https://localhost:3000/api are proxied to https://localhost:7001/api.
However, I got this error:
Error: self signed certificate
at Error (native)
at TLSSocket.<anonymous> (_tls_wrap.js:1060:38)
at emitNone (events.js:86:13)
at TLSSocket.emit (events.js:185:7)
at TLSSocket._finishInit (_tls_wrap.js:584:8)
at TLSWrap.ssl.onhandshakedone (_tls_wrap.js:416:38)
It seems to me that the error happens because of the REST API server in (1.) and the static server in (2.) use different certificates for their HTTPS configs.
The REST API server in (1.) uses a self signed JKS keystore for https.
I believe the static server in (2.) uses a default self-sign certificate that comes with browser sync.
So the two certificates are different. This is my guess for the cause of the error.
Any idea how to fix the problem? And what is the real cause of the error if my guess is wrong?
I could not find any instruction for how to use JKS as a certificate for the static server with browser-sync. In https://browsersync.io/docs/options, there is an instruction for how to put certificate to browser-sync, but that is a different type of certificate, and there was no field for password:
// Enable HTTPS mode with custom certificates
browserSync({
server: "./app",
https: {
key: "path-to-custom.key",
cert: "path-to-custom.crt"
}
});
so I am still clueless.
Any suggestions are greatly appreciated.
My gulp.js file for reference:
var gulp = require('gulp');
var browserSync = require('browser-sync').create();
var url = require('url');
var proxy = require('proxy-middleware');
gulp.task('browserSync', function() {
var proxyOptions = url.parse('https://localhost:7001/api/');
proxyOptions.route = '/api';
// requests to `https://localhost:3000/api/x/y/z` are proxied to `https://localhost:7001/api/x/y/`
browserSync.init({ //initialize a server with the given directory
open: true,
port: 3000,
https: true,
server: {
baseDir: '.',
middleware: [proxy(proxyOptions)]
}
});
});
gulp.task('watch', ['browserSync'], function() {
gulp.watch('app/*.html', browserSync.reload);
gulp.watch('app/**/*.html', browserSync.reload);
gulp.watch('app/**/*.js', browserSync.reload);
});
Related
My server has an SSL certificate, and the domain works fine with https. I ran "npm install peer", and then ran this javascript:
const { PeerServer } = require('peer');
const peerServer = PeerServer({
port: 9000,
path: '/myapp'
});
It worked, but only under http, and if secure:false. This URL returned the correct JSON:
http://www.example.com:9000/myapp
I then removed the 'port9000' PeerJS Server, and ran this javascript, so it would hopefully work with secure:true:
const { PeerServer } = require('peer');
const peerServer = PeerServer({
port: 443,
ssl: {
key: fs.readFileSync('my.key'),
cert: fs.readFileSync('my.crt')
},
path: '/myapp2'
});
This did not work. The following URL returned a blank directory, and no JSON:
https://www.example.com:443/myapp2
My server is running CentOS v. 7.8 64 bit, and it uses httpd.
Let me know if it will be easier to configure a port that is not "well-known" (i.e. not 443) to use for https communication with the PeerJS Server, so I can set "secure: true" in the client script.
I have a server running SignalR using .NET Core 3. The project was started with the template and I followed a guide (https://learn.microsoft.com/en-gb/aspnet/core/tutorials/signalr?tabs=visual-studio&view=aspnetcore-3.0).
I have created a clone of the project, and can successfully connect to the server and can receive messages as expected. This also means I added CORS.
I want to be able to use SignalR in a Node JS environment, but the connection stucks at "Negotiation"
I have created a brand new folder, ran npm init -y and npm i #microsoft/signalr.
Created a new js file called main.js, which looks like this:
const signalR = require("#microsoft/signalr");
let connection = new signalR.HubConnectionBuilder()
.withUrl("http://localhost:44336/chathub")
.configureLogging(signalR.LogLevel.Trace)
.build();
connection.on("send", data => {
console.log(data);
});
connection.start()
.then(() => connection.invoke("send", "Hello"));
after running it with node main.js
I get the following error in console
[2019-11-26T14:56:14.933Z] Debug: Starting HubConnection.
[2019-11-26T14:56:14.935Z] Debug: Starting connection with transfer format 'Text'.
[2019-11-26T14:56:14.936Z] Debug: Sending negotiation request: http://localhost:44336/chathub/negotiate.
[2019-11-26T14:58:18.890Z] Warning: Error from HTTP request. Error: read ECONNRESET
[2019-11-26T14:58:18.891Z] Error: Failed to complete negotiation with the server: Error: read ECONNRESET
[2019-11-26T14:58:18.892Z] Error: Failed to start the connection: Error: read ECONNRESET
[2019-11-26T14:58:18.892Z] Debug: HubConnection failed to start successfully because of error 'Error: read ECONNRESET'.
It seems like it's timing out. The server, client and nodejs app are all hosted locally.
I made sure to check that the signalr version installed with npm i match the version of server (3.0.1). I even extracted the js files in node_modules and used them for another client (made with the VS template) and it can connect just fine.
I have no clue how to debug any further. I tried to attach to the server using VS, but I couldnt get any information. The server is hosted using IIS Express (started via Visual Studio).
Any tips on how to debug any further? otherwise I might downgrade to a previous .NET Core version with another signalr version
My startup.cs code in VS
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
//services.AddControllersWithViews();
services.AddCors(options =>
{
options.AddPolicy("AllowAll",
builder =>
{
builder
.WithOrigins("http://localhost:44399", "http://localhost:44336", "https://localhost:44399", "https://localhost:44336")
.AllowCredentials()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
services.AddSignalR();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseCors("AllowAll");
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<ChatHub>("/chathub");
});
}
}
Don't know if this is the root cause or not, but I stumbled on this in my setup.
The default settings for IISExpress in Visual Studio do not listen on the same port for http and https. I was using the SSL port in my node.js file, but using the http protocol. I suspect your problem might be the same, since VS usually defaults to the 44000 range for SSL ports.
What confused me was the fact that my browser would pop up on the SSL port during debugging.
In my case, I checked ./Properties/launchSettings.json to get the ports being used:
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:63591",
"sslPort": 44357
}
},
Then updated my js file accordingly:
const signalR = require("#microsoft/signalr");
var hubConnection = new signalR.HubConnectionBuilder()
.configureLogging(signalR.LogLevel.Trace)
.withUrl("http://localhost:63591/chatHub")
.build();
And voila. Run the app in Visual Studio 2019, and then on the command line:
davek-win64% node app.js
[2020-08-05T21:20:15.483Z] Debug: Starting HubConnection.
[2020-08-05T21:20:15.490Z] Debug: Starting connection with transfer format 'Text'.
[2020-08-05T21:20:15.491Z] Debug: Sending negotiation request: http://localhost:63591/chatHub/negotiat
e.
[2020-08-05T21:20:15.591Z] Debug: Selecting transport 'WebSockets'.
[2020-08-05T21:20:15.592Z] Trace: (WebSockets transport) Connecting.
[2020-08-05T21:20:15.615Z] Information: WebSocket connected to ws://localhost:63591/chatHub?id=sYmFd19
_rNCR7q3mddpJBA.
[2020-08-05T21:20:15.616Z] Debug: The HttpConnection connected successfully.
[2020-08-05T21:20:15.616Z] Debug: Sending handshake request.
[2020-08-05T21:20:15.619Z] Trace: (WebSockets transport) sending data. String data of length 32.
[2020-08-05T21:20:15.621Z] Information: Using HubProtocol 'json'.
[2020-08-05T21:20:15.633Z] Trace: (WebSockets transport) data received. String data of length 3.
[2020-08-05T21:20:15.634Z] Debug: Server handshake complete.
[2020-08-05T21:20:15.635Z] Debug: HubConnection connected successfully.
Connected!
[2020-08-05T21:20:28.547Z] Trace: (WebSockets transport) data received. String data of length 74.
stackoverflow test
[2020-08-05T21:20:30.637Z] Trace: (WebSockets transport) sending data. String data of length 11.
[2020-08-05T21:20:31.197Z] Trace: (WebSockets transport) data received. String data of length 11.
You should consider your middleware order
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("AllowAll",
builder =>
{
builder
.WithOrigins("http://localhost:44399",
"http://localhost:44336",
"https://localhost:44399",
"https://localhost:44336")
.AllowCredentials()
.AllowAnyMethod()
.AllowAnyHeader();
});
});
services.AddSignalR();
services.AddControllersWithViews();
}
Try this to see if it work for you. You can refer to my other answer here
I need to run multiple Node apps on the same port. I've found out that I can run multiple node apps using one port, thanks to this SO question Running multiple Node (Express) apps on same port But it's not working for me probably bec. I'm using Restify unless I did something wrong somewhere.
I already have "app1" running on this one port using PM2 built using Restify. I've made another app "app2". The paths are like these:
/var/www/app1
/var/www/app2
with each app having common routes like these:
app.get('/', func...);
app.get('/about', func...);
app.post('/foo', func...);
app.post('/bar', func...);
I've set up "app1"'s last lines of code as: exports.app = app instead of app.listen(8080, function() { ... });
and, where app is
var app = restify.createServer({
name: 'app1'
});
"app2" is the same as well...
My main.js file (which is saved in /var/www/) is also built on Restify:
main
.use('/app`', require('./app1/index').app)
.listen(8080);
where main is
var main = restify.createServer({
name: 'main'
});
But I'm getting an error such as this when I type node main.js (I haven't tried with PM2 yet):
/var/www/node_modules/restify/node_modules/assert-plus/assert.js:45
throw new assert.AssertionError({
^
AssertionError: handler (function) is required
at process (/var/www/node_modules/restify/lib/server.js:76:24)
at argumentsToChain (/var/www/node_modules/restify/lib/server.js:84:13)
at Server.use (/var/www/node_modules/restify/lib/server.js:625:6)
at Object.<anonymous> (/var/www/main.js:47:8)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
Note: I've turned off all the apps running under PM2. There are no node apps running on any port.
The only way to do this effectively is to run an HTTP proxy configured to answer requests on a single port and pass them, based upon URL patterns, to servers running on other ports, a simple example of which can be found at A HTTP Proxy Server in 20 Lines of node.js Code.
In essence, your publicly visible proxy server runs on port 80 and you run other servers to handle specific requests.
So for example, if you run three HTTP servers, one as a forwarding proxy and two for specific functions such that:
proxy on port 80
server2 on port 8080 for requests matching regexp:/^\/first(?:\/.*)?$/
server3 on port 8081 for requests matching regexp:/^\/second(?:\/.*)?$/
where the only server that has a public connection is your proxy.
When the proxy receives a request for /first or /first/index.html, it forwards the request to server2 which returns a result document that the proxy then sends back to the original requester.
When it receives a request for /second/foo/bar/page.html, it does the same but using server3 to produce a result.
http-proxy is an implementation of this strategy which uses the http-proxy-rules plugin to process and forward requests based on URL patterns.
UPDATE
For the purposes of clarity, we assume proxy, server2, and server3 above represent individual node HTTP server instances listening on a single IP address but separate ports on the same machine.
Example:
var http = require('http'),
httpProxy = require('http-proxy'),
HttpProxyRules = require('http-proxy-rules');
// Set up proxy rules instance
// where
// any request for /hostname/app1 will be proxy-ed via SERVER2
// any request for /hostname/app2 will be proxy-ed via SERVER3
var proxyRules = new HttpProxyRules({
rules: {
'.*/app1/': 'http://localhost:8080', // TO SERVER2
'.*/app2/': 'http://localhost:8081' // TO SERVER3
}
});
// Create reverse proxy instance
var proxy = httpProxy.createProxy();
// Create http server on hostname:80 that leverages reverse
// proxy instance and proxy rules to proxy requests to
// different one of two target servers
http.createServer(function(req, res) { // PROXY
// a match method is exposed on the proxy rules instance
// to test a request to see if it matches against one
// of the specified rules
var target = proxyRules.match(req);
if (target) {
return proxy.web(req, res, {
target: target
});
}
res.writeHead(500, { 'Content-Type': 'text/plain' });
res.end('No rule found for this request');
}).listen(80);
// create a new HTTP server on localhost:8080 to process
// requests sent from the proxy
http.createServer(function (req, res) { // SERVER2
res.writeHead(200, { 'Content-Type': 'text/plain' });
var headers=JSON.stringify(req.headers,true,2);
res.write('request successfully proxy-ed to SERVER2!' + '\n' + headers);
res.end();
}).listen(8080,'localhost');
// create a new HTTP server on localhost:8081 to process
// requests sent from the proxy
http.createServer(function (req, res) { // SERVER3
res.writeHead(200, { 'Content-Type': 'text/plain' });
var headers=JSON.stringify(req.headers,true,2);
res.write('request successfully proxy-ed to SERVER3!' + '\n' + headers);
res.end();
}).listen(8081,'localhost');
Using this setup:
only the proxy server will be available externally on port 80
the servers running on ports 8080 & 8081 are only available on the local machine
requests received on the proxy at hostname:80 that match the /app1 path (and descendants) will be proxy-ed by the server running on localhost:8080
requests received on the proxy at hostname:80 that match the /app2 path (and descendants) will be served by the server running on localhost:8081
I am trying to improve the DEV experience in my Node. To do that, I want to:
a) restart my server when server-side code is changed
b) refresh the browser when client-side code is changes. In an effort to accomplish this, I began integrating nodemon and browserSync into my gulp script.
In my gulp script, I have the following task:
gulp.task('startDevEnv', function(done) {
// Begin watching for server-side file changes
nodemon(
{ script: input.server, ignore:[input.views] })
.on('start', function () {
browserSync.init({
proxy: "http://localhost:3002"
});
})
;
// Begin watching client-side file changes
gulp.watch([ input.css, input.js, input.html ], function() { browserSync.reload(); });
done();
});
When the above task runs, my browser opens to http://localhost:3000/. My app is visible as expected. However, in the console window, I notice:
Error: listen EADDRINUSE :::3002
I understand to some extend. I have app.set('port', process.env.PORT || 3002); in my server.js file. Yet, I thought that was purpose of setting the proxy value. Still, whenever I make a code change, I see the following related error in my console window:
[07:08:19] [nodemon] restarting due to changes...
[07:08:19] [nodemon] starting `node ./dist/server.js`
events.js:142
throw er; // Unhandled 'error' event
^
TypeError: args.cb is not a function
at Object.init (/Users/me/Website/Develop/node_modules/browser-sync/lib/public/init.js:25:25)
at null.<anonymous> (/Users/me/Website/Develop/gulpfile.js:142:25)
at emitNone (events.js:73:20)
at emit (events.js:167:7)
at Object.run (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:97:7)
at Function.run.kill (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:221:7)
at null.<anonymous> (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/run.js:333:7)
at emitOne (events.js:83:20)
at emit (events.js:170:7)
at restartBus (/Users/me/Website/Develop/node_modules/nodemon/lib/monitor/watch.js:162:7)
Me-MBP:Develop me$ events.js:142
throw er; // Unhandled 'error' event
^
Error: listen EADDRINUSE :::3002
at Object.exports._errnoException (util.js:856:11)
at exports._exceptionWithHostPort (util.js:879:20)
at Server._listen2 (net.js:1238:14)
at listen (net.js:1274:10)
at Server.listen (net.js:1370:5)
at Object.<anonymous> (/Users/me/Website/Develop/dist/server.js:70:8)
at Module._compile (module.js:399:26)
at Object.Module._extensions..js (module.js:406:10)
at Module.load (module.js:345:32)
at Function.Module._load (module.js:302:12)
At this point, my code changes do not appear in my browser. I do not understand what I'm doing wrong. I suspect I have my ports misconfigured. But, I'm not really sure how they should be setup.
By default BrowserSync uses port 3000. BrowserSync also uses port 3001 for the BrowserSync UI. For these two reasons, I thought I would set the port to 3002 in my server.js file and create the proxy shown above. What am I doing wrong?
You actually don't need to use gulp for this to work.
a) restart my server when server-side code is changed
Install nodemon globally using npm i -g nodemon then on your app folder do nodemon or nodemon ${index-file-of-your-app}.
b) refresh the browser when client-side code is changes.
Use browserify or webpack. I prefer using webpack; you may need to learn about the configuration a little bit but the good thing with webpack is that you don't need to refresh it. Once changes are found the changes will be reflected on the browser automatically. https://github.com/webpack/docs/wiki/hot-module-replacement-with-webpack
You can livereload both front and backend changes to the browser by using the 'livereload', 'connect-livereload', and 'nodemon' packages together. Also, this way you don't need Gulp or Grunt. Here's how the packages play together:
livereload opens a high port and notifies the browser of changed public files
connect-livereload monkey patches every served HTML page with a snippet that connects to this high port
nodemon is then used to restart the server on changed backend files
Set up livereload in Express
Set up the Express to both start livereload server watching the public directory and ping the browser during nodemon-induced restart:
const livereload = require("livereload");
const connectLivereload = require("connect-livereload");
// open livereload high port and start to watch public directory for changes
const liveReloadServer = livereload.createServer();
liveReloadServer.watch(path.join(__dirname, 'public'));
// ping browser on Express boot, once browser has reconnected and handshaken
liveReloadServer.server.once("connection", () => {
setTimeout(() => {
liveReloadServer.refresh("/");
}, 100);
});
const app = express();
// monkey patch every served HTML so they know of changes
app.use(connectLivereload());
Start Express with nodemon
Then you'd start the server with nodemon, for example, with a dedicated watch script by running npm run watch.
The key point here is to ignore the public directory that's already being watched by livereload. You can also configure files with non-default extensions, like pug and mustache, to be watched.
"scripts": {
"start": "node ./bin/www",
"watch": "nodemon --ext js,pug --ignore public"
},
You can read a longer explanation in "Refresh front and backend changes to browser with Express, LiveReload and Nodemon."
#mateeyow is right.
But if you want the browser to reload automaticaly, you also need livereload-plugin.
Enable webpack-hot-replacement only replace code in browser's memory, livereload-plugin do reload it.
See rock for example: https://github.com/orange727/rock/blob/master/app/templates/webpack/webpack.make.js#L255
Just as:
webpackConfig.plugins: [
new webpack.HotModuleReplacementPlugin(),
new LiveReloadPlugin({
appendScriptTag: true,
port: config.ports.livereload,
})];
I might be missing some context (e.g. I'm not sure what input represents), however, I think the npm module reload might solve your problem. Here's an example from the npm package page:
var express = require('express')
, http = require('http')
, path = require('path')
, reload = require('reload')
, bodyParser = require('body-parser')
, logger = require('morgan')
var app = express()
var publicDir = path.join(__dirname, '')
app.set('port', process.env.PORT || 3000)
app.use(logger('dev'))
app.use(bodyParser.json()) //parses json, multi-part (file), url-encoded
app.get('/', function(req, res) {
res.sendFile(path.join(publicDir, 'index.html'))
})
var server = http.createServer(app)
//reload code here
//optional reload delay and wait argument can be given to reload, refer to [API](https://github.com/jprichardson/reload#api) below
reload(server, app, [reloadDelay], [wait])
server.listen(app.get('port'), function(){
console.log("Web server listening on port " + app.get('port'));
});
The EADDRINUSE error is normally due to a connection already open on the specified port. This is probably due to a previous instance of the connection not being correctly closed when restarting the app.
Take a look at this gist and in particular try something like this in your gulp file:
'use strict';
var gulp = require('gulp');
var browserSync = require('browser-sync');
var nodemon = require('gulp-nodemon');
gulp.task('default', ['browser-sync'], function () {});
gulp.task('browser-sync', ['nodemon'], function() {
browserSync.init(null, {
proxy: "http://localhost:3002"
});
});
gulp.task('nodemon', function (cb) {
var started = false;
return nodemon({
script: 'app.js'
}).on('start', function () {
// to avoid nodemon being started multiple times
if (!started) {
cb();
started = true;
}
});
});
I have a JavaScript proxy server that often hangs up after having used it a while. This is the proxy code:
var express = require(["express"], function(){}),
http = require(["http"], function(){}),
port = (process.env.PORT || 8001),
server = module.exports = express(),
httpProxy = require(['http-proxy'], function(){});
var proxy = httpProxy.createProxyServer();
// SERVER CONFIGURATION
// ====================
server.configure(function() {
server.use(function(req, res, next) {
if (req.url.indexOf('/any/thing') === 0) {
//console.log(res);
proxy.web(req, res, {target: 'http://any.thing.com'});
} else {
next();
}
});
server.use('/anything', express["static"](__dirname + "/../public"));
server.use(express.errorHandler({
dumpExceptions: true,
showStack: true
}));
server.use(express.bodyParser());
server.use(server.router);
});
// Start Node.js Server
http.createServer(server).listen(port);
I am trying to do some tests with Nightwatch.js. The tests work up to a point, then the server crashes. In some tests this point is always reached at the same time, in others it depends when the server crashes and if it crashes at all.
This is the Error message:
C:...\node_modules\http-proxy\lib\http-proxy\index.js:119
throw err;
^
Error: socket hang up
at createHangUpError (_http_client.js:215:15)
at Socket.socketCloseListener (_http_client.js:247:23)
at Socket.emit (events.js:129:20)
at TCP.close (net.js:485:12)
Stopping Express server
What could be the reason for this? I was not able to figure it out in google.
The error is thrown when parallelly sending requests to the http-proxy.
The error can be prevented by installing a different version of http-proxy.
For me the error occured in http-proxy version 1.6.2.
I fixed the problem by installing version 1.0.0:
npm uninstall http-proxy
then
npm install http-proxy#1.0.0