http-proxy-middleware icon indicating copy to clipboard operation
http-proxy-middleware copied to clipboard

http-proxy-middleware v3 adds a '/' before query parameters ending up with 404

Open mnadeem opened this issue 1 year ago • 9 comments
trafficstars

Checks

Describe the bug (be clear and concise)

With the following

app.use(
  createProxyMiddleware('/api/v1/xyz', {
    target: 'https://example.com/api/v1/xyz',
    changeOrigin: true,
  })
);

if a request is being made https://myapp.com/api/v1/xyz?param1=value the proxied request is translating to https://example.com/api/v1/xyz/?param1=value resulting in 404. ( Extra / is being added )

This was not the case with v2 and even with v3 legacy mode.

Step-by-step reproduction instructions

1. Add proxy as described above
2. send the request with query params

Expected behavior (be clear and concise)

No "/" should be added,

How is http-proxy-middleware used in your project?

[email protected] proxy-app
├── [email protected]
└─┬ [email protected]
  └─┬ [email protected]
    └── [email protected]

What http-proxy-middleware configuration are you using?

app.use(
  createProxyMiddleware('/api/v1/xyz', {
    target: 'https://example.com/api/v1/xyz',
    changeOrigin: true,
  })
);


### What OS/version and node/version are you seeing the problem?

```shell
Windows 11, Node 20

Additional context (optional)

No response

mnadeem avatar Jul 06 '24 09:07 mnadeem

same here

emondora avatar Jul 10 '24 12:07 emondora

@chimurai mentioned in https://github.com/chimurai/http-proxy-middleware/issues/985#issuecomment-2067656422 that this is an upstream issue in the (unmaintained) http-proxy library. I only started seeing it after upgrading http-proxy-middleware from 2.0.6 to 3.0.0 though, which use the same http-proxy version, so that's a bit odd, but perhaps the issue somehow surfaced with #731 ?

Workaround (first attempt):

createProxyMiddleware({
  target: `https://otherhost/api`,
  changeOrigin: true,
  pathRewrite: (path) => path.replace(/\/$/, ""),
});

That doesn't handle URLs with query strings or hashes though.. Second attempt using lookahead to remove /'s followed by either ? or end of line:

createProxyMiddleware({
  target: `https://otherhost/api`,
  changeOrigin: true,
  pathRewrite: (path) => path.replace(/\/(?:(?=\?)|$)/, ""),
});

I have a feeling this one might not be perfect either though :/

danmichaelo avatar Jul 11 '24 22:07 danmichaelo

dupe of https://github.com/chimurai/http-proxy-middleware/issues/1000

Indeed related to change in https://github.com/chimurai/http-proxy-middleware/pull/731

Specifically: https://github.com/chimurai/http-proxy-middleware/pull/731/files#diff-07e6ad10bda0df091b737caed42767657cd0bd74a01246a1a0b7ab59c0f6e977L118

trailing slash issue should (ideally) be fixed in http-proxy

chimurai avatar Jul 12 '24 18:07 chimurai

trailing slash issue should (ideally) be fixed in http-proxy

The issue is that http-proxy hasn't been updated in 4 years... But this issue doesn't occur in the legacy version, so are you sure it happens in http-proxy

Netail avatar Jul 29 '24 19:07 Netail

Please fix this issue, other wise it will impact usage of latest version

mnadeem avatar Jul 30 '24 16:07 mnadeem

Hi @mnadeem. It's an open source project. You are welcome fix it upstream or suggest a fix.

chimurai avatar Jul 30 '24 18:07 chimurai

I am more wondering why this does occur with the createProxyMiddleware, but not the legacyCreateProxyMiddleware. Trying to investigate this a bit more...

Netail avatar Jul 30 '24 19:07 Netail

The legacy behaviour is on L30:

https://github.com/chimurai/http-proxy-middleware/blob/897611af512ffaf6add1601585952356fde8aec5/src/http-proxy-middleware.ts#L124-L131

To help investigation, it would be helpful to provide a minimal reproduction of the issue.

chimurai avatar Aug 04 '24 17:08 chimurai

I ran into this issue after upgrading from v2 to v3, where an extra / was being added before query parameters. On v2, a configuration like:

app.use(
  '/xyz.json',
  createProxyMiddleware({
    target: 'https://example.com/',
    changeOrigin: true,
  })
);

would correctly proxy https://myapp.com/xyz.json to https://example.com/xyz.json.

After upgrading to v3 and switching to the new API:

app.use(
  '/xyz.json',
  createProxyMiddleware({
    target: 'https://example.com/xyz.json',
    changeOrigin: true,
  })
);

the proxied request became https://example.com/xyz.json/, causing a 404 on our end.

As a workaround, I’ve explicitly controlled the path using pathRewrite and req.baseUrl:

app.use(
  createProxyMiddleware('/xyz.json', {
    target: 'https://example.com/',
    changeOrigin: true,
    pathRewrite: (_path, req) => req.baseUrl,
  })
);

This ensures that the trailing slash isn’t appended, and matches what the previous v2 version outputted.

adammccullagh avatar Dec 20 '24 11:12 adammccullagh

@adammccullagh I would suggest using req.originalUrl. e.g. /_next/static/css/app/layout.css resolved into /_next/static if it's checks on the path: /_next/:slug

Netail avatar Oct 07 '25 13:10 Netail

The legacy behaviour is on L30:

http-proxy-middleware/src/http-proxy-middleware.ts

Lines 124 to 131 in 897611a

 /** 
  * Incorrect usage confirmed: https://github.com/expressjs/express/issues/4854#issuecomment-1066171160 
  * Temporary restore req.url patch for {@link src/legacy/create-proxy-middleware.ts legacyCreateProxyMiddleware()} 
  * FIXME: remove this patch in future release 
  */ 
 if ((this.middleware as unknown as any).__LEGACY_HTTP_PROXY_MIDDLEWARE__) { 
   req.url = (req as unknown as any).originalUrl || req.url; 
 } 

To help investigation, it would be helpful to provide a minimal reproduction of the issue.

Hi @chimurai, Sorry, completely forgot about creating a repro, here you go https://github.com/Netail/repro-http-proxy-middleware :) The README explains how to reproduce the issue

Netail avatar Oct 07 '25 20:10 Netail