Skip to content

Instantly share code, notes, and snippets.

@frow
Last active August 13, 2019 17:01
Show Gist options
  • Save frow/eb0b649bce510587299741d34dc486c5 to your computer and use it in GitHub Desktop.
Save frow/eb0b649bce510587299741d34dc486c5 to your computer and use it in GitHub Desktop.
express + express.ws + node-http-proxy
import * as httpProxy from 'http-proxy';
import * as express from 'express';
import * as expressWs from 'express-ws';
import * as WebSocket from 'ws';
import * as cookieParser from 'cookie-parser';
const proxy = httpProxy.createProxyServer({
});
const httpServer = express();
const wsServer = expressWs(httpServer);
// cookie parser middleware
httpServer.use(cookieParser());
// custom middleware
httpServer.use((req, res, next) => {
// put your custom middleware here
next()
});
// proxy http requests to proxy target
httpServer.all("/my-http-route", (req, res) => {
proxy.web(req, res, {target: 'http://my-proxy-target'}, (error) => {
console.log('Could not contact proxy backend', error);
try {
res.send("The service is not available right now.");
} catch (e) {
console.log('Could not send error message to client', e);
}
});
});
// register websocket handler, proxy requests manually to backend
wsServer.app.ws("/my-websocket-path", (ws, req) => {
let headers = {};
// add custom headers, e.g. copy cookie if required
headers["cookie"] = req.headers["cookie"];
const backendMessageQueue: any[] = [];
let backendConnected = false;
let backendClosed = false;
let frontendClosed = false;
const backendSocket = new WebSocket(targetUrl, [], {
headers: headers
});
backendSocket.on('open', function() {
console.log('backend connection established');
backendConnected = true;
// send queued messages
backendMessageQueue.forEach(message => {
backendSocket.send(message);
});
});
backendSocket.on('error', (err) => {
console.log('error', err);
backendClosed = true;
if (!frontendClosed) {
ws.close();
}
frontendClosed = true;
});
backendSocket.on('message', (message) => {
// proxy messages from backend to frontend
ws.send(message);
});
backendSocket.on('close', () => {
console.log('Backend is closing');
backendClosed = true;
if (!frontendClosed) {
ws.close();
}
frontendClosed = true;
});
ws.on('message', (message) => {
// proxy messages from frontend to backend
if (backendConnected) {
backendSocket.send(message);
} else {
backendMessageQueue.push(message);
}
});
ws.on('close', () => {
console.log('Frontend is closing');
frontendClosed = true;
if (!backendClosed) {
backendSocket.close();
}
backendClosed = true;
});
});
export {
httpServer,
proxy
};
@frow
Copy link
Author

frow commented Oct 19, 2018

Hello, first thanks for the code,

Do you confirm this is the only way to add a custom header to either an http proxied request or a websocket one with express?

I would like to add a custom header from passport auth. I tried http-proxy-middleware but it seems the ws handshake doesnt take passport headers into account :(

I can add static headers listening to upgrade events but not custom headers depending on the previous middlewares (passport)

It's at least the only way on how I could get it to work reliably. Note that you need to copy the headers manually on the ws connection attempt on line 38. Hope that helps :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment