[Edit]
+
0
-
0

Node.js / Express.js - create proxy (forward request and response of HTTP protocol)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
// In this example you can find simple way how to forward multiple requests and responses in one Express.js application. // e.g.: // // [Proxy URLs] [Destination/Forwarded URLs] // // http://localhost:3000/website-1/ -> http://localhost:3000/ // http://localhost:3000/website-2/ -> http://localhost:5000/path/ // http://localhost:3000/website-3/ -> http://localhost:5500/resource/path/ // Finally we should be able to call the following URLs: // // http://localhost:3000/website-1/ // http://localhost:3000/website-1/path/to/resource/ // http://localhost:3000/website-2/ // http://localhost:3000/website-2/path/to/resource/ // http://localhost:3000/website-3/ // http://localhost:3000/website-3/path/to/resource/ // ^^^^^^^^^^^^^^^^^^ // |||||||||||||||||| // this part will be forwarded to the destination URL // -------------------------------------------------- const path = require('path'); const http = require('http'); const express = require('express'); // npm install express const createExpression = require('path-to-regexp'); // this package in correct version is automatically attached by Express.js to construct routes expressions // -------------------------------------------------- const joinPaths = (...parts) => { return path.posix.join(...parts); }; const findWildcard = (expression, path) => { const matches = expression.exec(path); if (matches.length > 0) { return matches[matches.length - 1]; } return null; }; const createComposition = (aPath, bPath, bSearch) => { let path = joinPaths(aPath ?? '', bPath ?? ''); if (bSearch) { const search = bSearch.toString(); if (search) { return path + '?' + search; } } return path; }; /** * Adds HTTP proxy from `${proxyPath}/*` to `${dstUrl}/*` in express application. * * @param {*} expressApp express application * @param {String} proxyPath path that we want to redirect, e.g. '/my-application' * @param {String} dstUrl URL that we want to handle, e.g. 'http://localhost:3000' * @param {*} proxyAgent HTTP aget that is used to make requests (optional) */ const createProxy = (expressApp, proxyPath, dstUrl, proxyAgent = null) => { const parsedUrl = new URL(dstUrl); if (parsedUrl.search) { throw new Error('Incorrect destination URL (query component is not permitted).'); } if (proxyAgent == null) { proxyAgent = new http.Agent({ keepAlive: true, maxSockets: 100 }); } const routePath = joinPaths(proxyPath, '*'); const routeExpression = createExpression(routePath); expressApp.all(routePath, (srcRequest, srcResponse) => { const srcPath = srcRequest.url; const srcQuery = srcRequest.query; const srcWildcard = findWildcard(routeExpression, srcPath); // finds raw not decoded wildcard parameter const dstRequest = http.request({ agent: proxyAgent, protocol: parsedUrl.protocol, hostname: parsedUrl.hostname, port: parsedUrl.port, path: createComposition(parsedUrl.pathname, srcWildcard, new URLSearchParams(srcQuery)), query: [], method: srcRequest.method, headers: srcRequest.headers }); dstRequest.on('response', (dstResponse) => { if (dstResponse.statusCode) { srcResponse.status(dstResponse.statusCode); } if (dstResponse.headers) { srcResponse.set(dstResponse.headers); } dstResponse.pipe(srcResponse); }); dstRequest.on('error', (e) => { console.error(e); srcResponse .status(500) .send(`Endpoint request error! Check if ${dstUrl} endpoint is working.`); }); srcRequest.pipe(dstRequest); }); }; // -------------------------------------------------- const SERVER_PORT = 3000; const app = express(); // Put your aplication routes before '/website-1', '/website-2' and '/website-3' createProxy(app, '/website-1', 'http://localhost:3000/'); createProxy(app, '/website-2', 'http://localhost:5000/path/'); createProxy(app, '/website-3', 'http://localhost:5500/resource/path/'); app.listen(SERVER_PORT, () => console.log(`Server is listening on port ${SERVER_PORT}.`));