http-proxy-middleware: pathFilter not working as expected - browser-sync

I am trying so setup a npm-based HTML development environment using two servers. One hosts my HTML app of static files (standard way: http://localhost:8080) while the other exposes an application api running locally(http://127.0.0.1:57146/api/someEntity). The latter is beyond my control.
Calling the api URLs directly from my app brings up CORS issues. So i want to setup a proxy that redirects my calls from http://localhost:8080/apiBase/someEntity to http://127.0.0.1:57146/api/someEntity... hoping to avoid the CORS problems that way.
I am using lite-server, which builds on top of Browsersync.
Since my static app files do not need redirection, they should not be affected by the proxy.To specify, which calls are redirected, i am trying to use the "pathFilter" field in the options. But i cannot get that functioning. Instead all calls are always proxied to http://127.0.0.1:57146. "pathRewrite" does not seems to work, either. So it seems like i am missing something basic here. What am i doing wrong?
Here is my config file:
//bs-config.cjs
const { createProxyMiddleware } = require('http-proxy-middleware');
const apiProxy = createProxyMiddleware({
target: "http://127.0.0.1:57146/",
pathFilter:"apiBase/",
pathRewrite: {
"apiBase/": "api/"
},
logger: "console",
logLevel: "debug"
});
module.exports = {
port: 8080,
index: "parent.htm",
startPath: "parent.htm",
cors: true,
server: {
baseDir: "./dist",
index: "parent.htm",
cors: true,
middleware: [ apiProxy ]
}
};

With the help of a (very) patient backend guy, i finally found a solution.
We could not get "pathRewrite" to work, but after getting the filter functioning (by changing some syntax), tweaking the paths ended up in a working setup.
//bs-config.cjs
const { createProxyMiddleware } = require('http-proxy-middleware');
const proxy_filter = function (path, req) {
const regx = new RegExp("/apiBase");
return path.match(regx);
};
const proxy_options = {
target: "http://127.0.0.1:57146/api/",
changeOrigin: true,
logger: "console",
logLevel: "debug"
}
const apiProxy = createProxyMiddleware(proxy_filter, proxy_options);
module.exports = {
port: 8080,
index: "parent.htm",
startPath: "parent.htm",
server: {
baseDir: "./dist",
index: "parent.htm",
middleware: [
apiProxy
]
}
};

Related

I can't setup proxy in mern stack(react-vite) and do not know the reason

I'm developing mern stack web application with react from vite.js and have a problem to deal with proxy.
my client side runs at http://localhost:3000 and server side runs at http://localhost:5000.
usually I use http-proxy-midlleware to connect my server and client like below
src/setupProxy.jsx
const { createProxyMiddleware } = require('http-proxy-middleware');
module.exports = function(app){
app.use(
createProxyMiddleware('/api', {
target: 'http://localhost:5000',
changeOrigin: true
})
)
};
However, It didn't work and still sent to localhost:3000 when I post data to server with axios. I googled it and figured out that with vite.js I need to use vite.config.js
so I set up vite.config.js like below
import { defineConfig, HttpProxy } from 'vite'
import react from '#vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],
server: {
host: true,
port : 3000,
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true
}
}
},
})
and tried axios call again.
const result = await axios.post('api/users/login', dataToSubmit)
.then(res => res.data);
return result;
However, contrary to my expectation, It still sent to 3000 and I do not have a clue about what is going wrong :/
xhr.js:210 POST http://localhost:3000/api/users/login 404 (Not Found)
could you tell me how to fix it? thanks for reading, your help will be appreciated.
It's required to specify secure: false like this. Reference
export default defineConfig({
plugins: [react()],
server: {
host: true,
port : 3000,
proxy: {
'/api': {
target: 'http://localhost:5000',
changeOrigin: true,
secure: false
}
}
},
})
I had this problem too.
My backend runs on http://localhost:8080, while my frontend runs on http://localhost:3000.
To resolve the cross-origin issue, I used the proxy alternative, but every request was returning a 404 error.
My solution was to add the rewrite: (path) => path.replace(/^\/api/, "") function in the vite settings file.
Finally, the final result of the file was:
import { defineConfig } from "vite";
import react from "#vitejs/plugin-react";
// https://vitejs.dev/config/
export default defineConfig({
server: {
proxy: {
"/api": {
target: "http://127.0.0.1:8080",
changeOrigin: true,
secure: false,
ws: true,
rewrite: (path) => path.replace(/^\/api/, ""),
},
},
port: 3000,
},
plugins: [react()],
});
Your port in vite.config.js file is set to 3000. So you have to set your target in src/setupProxy.jsx to 'http://localhost:3000'.
hope it helps

How to set up http-proxy-middleware on a dynamic route?

I'm trying to proxy some asset routes where a dynamic part of the path comes from a config file. I had this working using the request library, but I can't quite get it working with http-proxy-middleware.
Here's the code that works when I use the request library:
const assets = express.Router();
app.use(`/${p.name}/assets`, assets);
assets.get('*', async (req, res) => {
return request(`${p.address}/${p.version}/assets${req.path}`).pipe(res);
});
I've tried a few different variations with http-proxy-middleware, and none of these work. Example 1:
app.use(
`/${p.name}/assets`,
httpProxy({
target: `${p.address}`,
changeOrigin: true,
pathRewrite: {
[`^${p.name}`]: `${p.version}`,
},
})
);
Example 2:
app.use(
`/${p.name}/assets`,
httpProxy({
target: `${p.address}`,
changeOrigin: true,
pathRewrite: function(path) {
return path.replace(p.name, p.version);
}
})
);
I've also tried using /${p.name}/assets/** as the first argument to app.use, and I've also tried adding a /assets to the end of both the key and value in the pathRewrite object. The result is always the same: I get a 302 for the asset requested by the browser.
I've even tried adding a middleware function right before the httpProxy call that logs to the console so that I know my request is hitting the correct route:
app.use(
`/${p.name}/assets`,
(req, _res, next) => {
console.log("I'm an asset proxy, short and stout: ", req.url);
next();
},
httpProxy({
target: `${p.address}`,
changeOrigin: true,
pathRewrite: {
[`^${p.name}`]: `${p.version}`,
},
})
);
But I don't ever see that output. Probably a simple mistake. Perhaps my first argument to app.use just isn't right? Help appreciated!
Update
I also tried a combination of the old way and the new. I mounted a new router on /${p.name}/assets, and after discovering the onProxyRequest option, I added a function there to log some output.
const assets = express.Router();
app.use(`/${p.name}/assets`, assets);
assets.use(
'*',
httpProxy({
target: p.address,
changeOrigin: true,
pathRewrite: {
[`^${p.name}`]: p.version,
},
onProxyReq: (proxyReq, req, res) => {
console.log("Hello I'm being proxied now! ", proxyReq, req, res);
},
})
);
Still getting a 302, and I never see the output from the onProxyReq function.
Documentation has custom router option.
-
const proxyTable = {
'integration.localhost:3000': 'http://localhost:8001', // host only
'staging.localhost:3000': 'http://localhost:8002', // host only
'localhost:3000/api': 'http://localhost:8003', // host + path
'/rest': 'http://localhost:8004', // path only
};
const options = {
target: 'http://localhost:8000',
router: proxyTable,
};
const myProxy = createProxyMiddleware(options);
or
function customRouter(req) {
// I dont know what "p" stands for
// check the req object to see which property you want to modify
console.log(req)
const { hostname } = req
const hostName = hostname.split('.')[0]
return `https://${hostName}.sub.domain.com`
}
then add this option:
router: customRouter
Can you check your installed version - looks like you are using the v0.x.x.
interface to the http-proxy-middleware package. Latest is version 2.X.X and it exposes the following function
const { createProxyMiddleware } = require('http-proxy-middleware');
app.use(
`/${p.name}/assets`,
createProxyMiddleware({
target: `${p.address}`,
changeOrigin: true,
pathRewrite: {
[`^${p.name}`]: `${p.version}`,
},
})
);

Unable to Proxy AWS EMR Jupyter-Notebook's socket through node application. Failed to load kernel

We have our node application which we want to use to proxy jupyter notebook running on AWS EMR. I am able to proxy all my http request from my node application using http-proxy-middleware. But for some reason I am unable to proxy web-socket requests. Because of this I am able to create a new notebook but unable to start the kernel. Here is my proxy middleware
'use strict';
const proxy = require('http-proxy-middleware');
module.exports = proxy({
target: 'http://<EMR master_node IP>:<Port>',
ws: true,
changeOrigin: true,
// onProxyReq: (proxyReq, req, res) => {
// proxyReq.removeHeader('Upgrade');
// proxyReq.removeHeader('Connection');
// proxyReq.setHeader('Upgrade', 'websocket');
// proxyReq.setHeader('Connection', 'upgrade');
// },
secure: true,
loglevel: 'debug'
});
I tried to manually add the headers as well which you see as commented but it did not help. Also for the server application I have upgrade enabled.
server.on('upgrade', proxy.upgrade);
Any help would be greatly appreciated.
Here's a working solution:
handleRequestHeaders = function (proxyRequest, request) {
proxyRequest.setHeader('Host', request.headers['host']) ;
proxyRequest.setHeader('X-Forwarded-For', request.connection.remoteAddress) ;
proxyRequest.setHeader('X-Real-IP', request.connection.remoteAddress)
if (request.headers['upgrade']) {
proxyRequest.setHeader('Upgrade', request.headers['upgrade']) ;
}
proxyRequest.setHeader('Connection', request.headers['upgrade'] ? 'upgrade' : 'close') ;
proxyRequest.setHeader('Referer', 'http://localhost') ;
proxyRequest.removeHeader('Origin') ;
}
module.exports = proxy({
target: 'http://<EMR master_node IP>:<Port>',
ws: true,
changeOrigin: true,
onProxyReq: handleRequestHeaders,
onProxyReqWs handleRequestHeaders
});

NodeJS Subdomain w/ vhost and greenlock-express

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
}
}
});

Getting browser-sync to play nice with ember-cli and a localhost API server

I've been trying to get browser-sync to play nice with ember-cli via ember-cli-browser-sync (installed via "ember-cli-browser-sync": "git://github.com/dylanharrington/ember-cli-browser-sync.git" in package.json as it isn't on the npm registery) with my localhost API server, but have been unable to get it to work.
Just doing
serverMiddleware: function(config) {
config.options.liveReload = false;
browserSync({
injectChanges: true,
reloadDelay: 10,
notify: false,
open: false,
proxy: "localhost:4200"
});
},
Works wonderfully for a local device, but fails at accessing my api at http://localhost:8000/api/1 from an external device (iPhone).
I tried to extend the proxy settings to include my local API via:
var url = require('url'),
proxy = require('proxy-middleware');
serverMiddleware: function(config) {
config.options.liveReload = false;
var proxyOptions = url.parse('http://localhost:8000/api/1');
browserSync({
injectChanges: true,
reloadDelay: 10,
notify: false,
open: false,
proxy: {
target: 'localhost:4200',
middleware: [proxy(proxyOptions)]
}
});
});
Which basically serves the API to my external URL provided by BrowserSync.
So I tried to utilise server:
serverMiddleware: function(config) {
config.options.liveReload = false;
var proxyOptions = url.parse('http://localhost:8000/api/1');
console.log(proxyOptions);
// proxyOptions.route = '/api';
browserSync({
injectChanges: true,
reloadDelay: 10,
notify: false,
open: false,
port: 3000,
server: {
baseDir: "./",
routes: {
"/app": "app",
"/assets": "dist/assets",
},
index: "app/index.html",
middleware: function (req, res, next) {
console.log(req.url);
next();
}
}
});
},
Which serves the correct index, and all the asset files, but causes an error with ember.
Does anyone have any experience doing this and which path I should try next? Is there a different NPM package I should try to use to proxy my API?
I gave up trying to solve this myself and ended up just using XIP, which might suit your needs.

Resources