Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Setting "proxy" in package.json Fails for WebSockets #5280

Open
Kent-H opened this issue Oct 3, 2018 · 48 comments
Open

Setting "proxy" in package.json Fails for WebSockets #5280

Kent-H opened this issue Oct 3, 2018 · 48 comments
Milestone

Comments

@Kent-H
Copy link

@Kent-H Kent-H commented Oct 3, 2018

Expected Behavior

Setting "proxy" in package.json should proxy WebSockets to specified server.
(As documented here: "The proxy option supports HTTP, HTTPS and WebSocket connections.")

Actual Behavior

Proxy does not work for WebSocket connections.

Reproducible Demo

No time for this atm. ¯\(ツ)

@gaearon
Copy link
Member

@gaearon gaearon commented Oct 3, 2018

Did it work in 1.x? Or is this a regression?

@Kent-H
Copy link
Author

@Kent-H Kent-H commented Oct 3, 2018

Current workaround:

Create src/setupProxy.js, with:

const proxy = require("http-proxy-middleware")

module.exports = app => {
  app.use(proxy("/websocket", {target: "http://localhost:8080", ws: true}))
}

@Timer Timer added this to the 2.x milestone Oct 3, 2018
@Kent-H
Copy link
Author

@Kent-H Kent-H commented Oct 3, 2018

In 1.x, it was possible to specify more advanced options, including "ws":true.

Though I don't know what the handling by the simple "proxy": < url > was.

@Timer
Copy link
Contributor

@Timer Timer commented Oct 3, 2018

OK, sounds like this isn't a regression but a proposal to auto-detect and proxy websockets in the simple proxy mode.

@Kent-H
Copy link
Author

@Kent-H Kent-H commented Oct 3, 2018

At minimum, reality is out of sync with the documentation.
(Ended up wasting a couple hours trying to figure out why I couldn't connect.)

Though I would recommend making WebSocket proxying work by default.

@gaearon
Copy link
Member

@gaearon gaearon commented Oct 4, 2018

It was supposed to work in 1.x too.

@Timer Timer modified the milestones: 2.x, 2.0.x Oct 4, 2018
@avdeev
Copy link

@avdeev avdeev commented Oct 9, 2018

I reproduce with issue.

  app.use(proxy('/ws', {
    target: 'http://localhost:3007',
    ws: true,
  }));
[HPM] Upgrading to WebSocket
events.js:167
      throw er; // Unhandled 'error' event
      ^

Error: read ECONNRESET
    at TCP.onStreamRead (internal/stream_base_commons.js:111:27)
Emitted 'error' event at:
    at emitErrorNT (internal/streams/destroy.js:82:8)
    at emitErrorAndCloseNT (internal/streams/destroy.js:50:3)
    at process._tickCallback (internal/process/next_tick.js:63:19)

@ivosh
Copy link

@ivosh ivosh commented Nov 8, 2018

I can confirm that the following setup worked in 1.x:

"proxy": {
  "/api": {
    "target": "ws://localhost:4000",
     "ws": true
   }
}

but this no longer works in 2.1.1's package.json:
"proxy": "ws://localhost:4000"

I get the following error message upon npm start:
When "proxy" is specified in package.json it must start with either http:// or https://

That said, I will be happy to test any fix you throw at my direction.

@mxschmitt
Copy link

@mxschmitt mxschmitt commented Nov 15, 2018

Hey,
I tried to investigate some time to analyze this issue and found a possible fix. Would be great if some of you could test it. Once it works for you too, I will open a PR.
https://github.com/mxschmitt/create-react-app/commit/acc5ab13da20d777012f53578b76266d5521cff0
To test it, simply edit the following file: node_modules/react-dev-utils/WebpackDevServerUtils.js and add to line 327 to the return condition req.upgrade || like in the commit above.
Best regards
Max

@ivosh
Copy link

@ivosh ivosh commented Nov 15, 2018

@mxschmitt, thank you for your email.
I've tried your patch but it did not work for me. I was still receiving error message:
When "proxy" is specified in package.json it must start with either http:// or https://.

So I've hacked the following fix and it works for my setup:
ivosh@1fa22ae7a2c54903f6c69f60f8b29c24487ff812
I've also tried to incorporate your patch into it and observed no difference (works with and also without).

@mxschmitt
Copy link

@mxschmitt mxschmitt commented Nov 15, 2018

@ivosh You don't have to use ws:// as protocol for your websocket. Just use http:// which will work fine in my case.

@ivosh
Copy link

@ivosh ivosh commented Nov 15, 2018

@mxschmitt, you are right, thank you for pointing this out. So in my case, even when all communication happens over websockets, specifying "proxy": "http://localhost:4000" is sufficient for the communication to be proxied.
Your change is not needed in my setup.

@bsorbo
Copy link

@bsorbo bsorbo commented Nov 16, 2018

+1'ing the change @mxschmitt is proposing, this does fix the issue for me.

For background, the problem locally is that firefox is sending 'text/html' in 'Accept' when opening the websocket connection, which causes the default proxy heuristic to -not- proxy the request:

    return (
      req.method !== 'GET' ||
      (mayProxy(pathname) &&
        req.headers.accept &&
        req.headers.accept.indexOf('text/html') === -1)
    );

I agree the presence of the 'upgrade' header should force proxying just like a non-GET request, unless there's a case I'm missing.

@mxschmitt
Copy link

@mxschmitt mxschmitt commented Feb 7, 2019

Yey, the stale bot has closed my PR: #5841....

@jamescostian
Copy link

@jamescostian jamescostian commented Feb 20, 2019

I've been wrestling with this issue for a while now, and the workarounds are very annoying, especially when you have cookies involved. Is there any reason why #5841 isn't being merged? It looks like one of the builds failed, but it seems to be an issue completely unrelated to the code change in that PR.

@mxschmitt maybe if you add a comment to the code in your PR, the CI will rerun and hopefully there won't be any build issues this time?

@dvlpr-eth
Copy link

@dvlpr-eth dvlpr-eth commented Aug 27, 2019

Try this:
http://saule1508.github.io/create-react-app-proxy-websocket/

@Kent-H
Copy link
Author

@Kent-H Kent-H commented Sep 5, 2019

@hamidnoei This workaround has already been discussed.

@avkonst
Copy link

@avkonst avkonst commented Dec 18, 2019

@avdeev Alexey, have you found a solution for the issue you described in this comment: #5280 (comment) ? I have got the same.

@goldmont
Copy link

@goldmont goldmont commented May 3, 2020

+1

@aaroncowie
Copy link

@aaroncowie aaroncowie commented May 7, 2020

FYI according to #6497 there was a new PR #6515 but that has been closed without comment after the stale bot flagged it again.

@robyn3choi
Copy link

@robyn3choi robyn3choi commented Jun 10, 2020

+1

@ferrybig
Copy link

@ferrybig ferrybig commented Jun 19, 2020

Workaround: Use Firefox, for some reason this feature is not broken on Firefox.

I typically do my local development on Firefox, and websocket proxying works there out of the box, and I was surprised to see that this was broken on Chrome, wasted alot of hours on this bug

@williamstein
Copy link

@williamstein williamstein commented Jun 27, 2020

The docs for proxy linked to in the original description have moved here.

@supertick
Copy link

@supertick supertick commented Jul 11, 2020

Verified this is broken in Chrome 77.0.3865.75 (Official Build) (64-bit)
and working in FireFox 76.0.1 (64-bit)

Agree with @Kent-H - preferred behavior would be "work out of the box"
Interesting its a Chrome only issue

Burned hours thinking it was my code preventing the socket connection.

I'd give big nerd creds to anyone involved in fixing it !

@opandey007
Copy link

@opandey007 opandey007 commented Aug 17, 2020

Current workaround:

Create src/setupProxy.js, with:

const proxy = require("http-proxy-middleware")

module.exports = app => {
  app.use(proxy("/websocket", {target: "http://localhost:8080", ws: true}))
}

can u tell me how can i use setupProxy.js and i removed proxy from packege.json so how can i redireect my api to proxy

@davidmwhynot
Copy link

@davidmwhynot davidmwhynot commented Sep 13, 2020

I can also confirm this is broken in chrome but working in firefox. This is probably unrelated, but I have HTTPS=true, which is working for wss on firefox. I say it's unrelated b/c chrome breaks when using ws or wss.

At the very least, the docs should be updated to indicate that this is currently broken for websockets in chrome. It's a little misleading to say that it works websockets when that's only true for certain browsers.

@MikeDev96
Copy link

@MikeDev96 MikeDev96 commented Sep 14, 2020

I also have the same issue, proxy not working for Chrome but is for Firefox.

@gregorbg
Copy link

@gregorbg gregorbg commented Oct 1, 2020

+1

@ovasylenko
Copy link

@ovasylenko ovasylenko commented Oct 4, 2020

any news on the issue?

@thecactoos
Copy link

@thecactoos thecactoos commented Oct 29, 2020

+1

@DominicTobias-b1
Copy link

@DominicTobias-b1 DominicTobias-b1 commented Feb 22, 2021

The issue for me is that the websocket request never reaches the proxy, e.g.

module.exports = app => {
  app.use((req, res, next) => {
    console.log(req.url)
    next()
  })
}

I see HTTP requests there but none on the localhost:{port} for ws or wss?

The only solution I can think of atm is to start another local server in setupProxy.js just to proxy websocket requests on another port since they aren't passed through here?

@lanshunfang
Copy link

@lanshunfang lanshunfang commented Apr 12, 2021

According to the doc, this works for me:

    app.use(
        createProxyMiddleware(
           "/subscriptions",
            {
                target: 'http://localhost:4000',
                ws: true
            })
    );

Note that, the "/subscriptions", should be moved into createProxyMiddleware, not within app.use directly.

@floriancargoet
Copy link

@floriancargoet floriancargoet commented May 5, 2021

In WebpackDevServerUtils.js, the context() function, which decides if a request must be proxied, returns a different result between Chrome and Firefox.
It's because in the case of a WebSocket, Chrome doesn't send the "Accept" header but Firefox does (at least in my tests with socket.io).
If I change the function to return true when there's no accept header, my websocket connection is proxied as expected.

@floriancargoet
Copy link

@floriancargoet floriancargoet commented May 5, 2021

My solution was to use both techniques:

  • add "proxy": "http://localhost:8000" in package.json, to handle most cases
  • add a src/setupProxyFile.js just for socket.io :
const createProxyMiddleware = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    createProxyMiddleware("/socket.io/", {
      target: "http://localhost:8000/",
      ws: true,
    })
  );
};

Hope it helps someone.

@no1melman
Copy link

@no1melman no1melman commented Jun 22, 2021

When I did the above steps my websocket to my dotnet app worked a treat - however, now my hot reloading isn't working with this error

webpackHotDevClient.js:60 WebSocket connection to 'ws://localhost:3000/sockjs-node' failed: Invalid frame header

Anyone with an idea on what is happening?

my setup

const proxy = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    "/api",
    proxy({
      target: "http://localhost:5000",
      changeOrigin: true,
    })
  );
  app.use(
    "/ws",
    proxy({ target: "http://localhost:5000", ws: true, changeOrigin: true })
  );
};

@krodyrobi
Copy link

@krodyrobi krodyrobi commented Jul 4, 2021

@no1melman I also see the same issue as you.
What I could tell is that somehow when the /ws proxy gets upgraded it also tries to upgrade /sockjs-node or something along these lines.

Adding a ws: true proxy in setupProxy,js and using the path will cause the live reload socket to fail.
One does not need to have an outgoing ws to the path any request will cause the issue.
Paths and rewrites seem to be of no significance.

Socket implementation: socket.io v4

@krodyrobi
Copy link

@krodyrobi krodyrobi commented Jul 4, 2021

@no1melman not sure if this helps but for some reason the following no longer affects sockjs and forwards as expected..
Not even sure how it differs (stumbled upon it randomly on stackoverflow) but it does, you can also try it.

const proxy = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    proxy("/api", {        // <-- notice the pattern is not in use but in the proxy method
      target: "http://localhost:5000",
      changeOrigin: true,
    })
  );
  app.use(
    proxy("/ws", {          // <-- notice the pattern is not in use but in the proxy method
      target: "http://localhost:5000",
      ws: true,
      changeOrigin: true
    })
  );
};

@sancelot
Copy link

@sancelot sancelot commented Jul 8, 2021

My question may be silly, but I have multiple websockets in my backend :
a broadcast server on eg port 5000
a raw socket on port 5001
and json rpc websocket on port 5002

How to deal with all these ??????

@Eliarh
Copy link

@Eliarh Eliarh commented Aug 1, 2021

+1

@lilrooness
Copy link

@lilrooness lilrooness commented Apr 13, 2022

+1

@AaronNGray
Copy link

@AaronNGray AaronNGray commented May 21, 2022

with :-

  "proxy": {
    "/graphql": {
      "target": "http://localhost:3030",
      "ws": true
    }
  }

I am getting the following :-

$ react-scripts start
(node:16776) [DEP0111] DeprecationWarning: Access to process.binding('http_parser') is deprecated.
(Use `node --trace-deprecation ...` to show where the warning was created)
When specified, "proxy" in package.json must be a string.
Instead, the type of "proxy" was "object".
Either remove "proxy" from package.json, or make it a string.
error Command failed with exit code 1.

@AaronNGray
Copy link

@AaronNGray AaronNGray commented May 21, 2022

With Chrome and ApolloServer and plain "proxy": "http://localhost:3030" I am getting :-

WebSocket connection to 'ws://localhost:3000/sockjs-node/023/0qlhbfvd/websocket' failed: WebSocket is closed before the connection is established.
push../node_modules/sockjs-client/lib/transport/websocket.js.WebSocketTransport.close @ websocket.js:80

Similar on FireFox :-

The connection to ws://localhost:3000/sockjs-node/521/go41gmjr/websocket was interrupted while the page was loading.

@AaronNGray
Copy link

@AaronNGray AaronNGray commented May 21, 2022

Okay I tried #5280 (comment) and it worked with latest subscriptions implementation on Apollo Server on FireFox and Chrome, but not on MS Edge. I will have to look into that later its not throwing up any errors, but is not working on MS Edge, it might be my code seeing as how near Chrome and Edge are.
On adding credentials: 'include' to new HttpLink MS Edge started working too. But found out my subscriptions were not going through websockets anyway : |

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

Successfully merging a pull request may close this issue.