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

Server-sent events not working #921

Open
davej opened this issue Dec 3, 2015 · 21 comments
Open

Server-sent events not working #921

davej opened this issue Dec 3, 2015 · 21 comments

Comments

@davej
Copy link

davej commented Dec 3, 2015

It works for a period of time and then I get an error in the browser console: "net::ERR_INCOMPLETE_CHUNKED_ENCODING"… after this it stops working.

Works perfectly if I load the site directly (i.e. not through the proxy).

Code I'm using to proxy request/responses is simply:

proxy.web(req, res, { target = 'http://localhost:8888' });

Previous issue was: #357

@jcrugzz
Copy link
Contributor

jcrugzz commented Dec 3, 2015

@davej would love to have a test case for this. Can you reproduce in a node only test so we could add that to our test suite? Thanks!

@aaronmaturen
Copy link
Contributor

Hey friends,

SSE seems to be working for me, but I created a test and example for SSE here: #922

@davej
Copy link
Author

davej commented Dec 7, 2015

@aaronmaturen: Thanks for that.

I was able to figure out what the issue is. node-http-proxy is timing out the response after 2 minutes of inactivity.

If you change the connection handler on line 57 of the sse example to the code below then you should be able to recreate it:

sse.on('connection', function(client) {
  client.res.setTimeout(0); // Disable timeout
  var count = 0;
  setTimeout(function(){
    client.send('message #' + count++);
  }, 1500);

  setTimeout(function(){
    client.send('message #' + count++);
  }, 150000);
});

On the proxy (8003), it times out after about 2 minutes (Chrome 46), with net::ERR_INCOMPLETE_CHUNKED_ENCODING and the second message is not received.

On the raw SSE server (9003), it doesn't time out and the second message is received.

Is there a way to get the proxy to respect the timeout characteristics of the SSE server

@aaronmaturen
Copy link
Contributor

It looks like the ws proxy prevents the connection from timing out by setting the timeout option to 0; you may be able to the same with this one. I tried setting the timeout to 1000ms and it threw the error when I expected. When I set the timeout to 0 and the interval to 150000, chrome didn't throw the error again but the tab stopped showing the loading ticker after ~2minutes

//
// Basic Http Proxy Server
//
var proxy = new httpProxy.createProxyServer();
http.createServer(function (req, res) {
  proxy.web(req, res, {
    target: 'http://localhost:9003',
    timeout: 0 // prevent the proxy from killing the connection
  });
}).listen(8003);

@davej
Copy link
Author

davej commented Dec 7, 2015

Yes, it's easy enough to fix when you know what's wrong, thanks for your help.

I guess I can close this issue unless it's worth considering setting the timeout to 0 for websocket and SSE connections? Or is that a bit too magical?

@aaronmaturen
Copy link
Contributor

There is a setupSocket method in common.js that not only sets the timeout but also sets no delay and keep alive on the current socket. This is currently called in ws-incoming.js after the upgrade event has been emitted for web-sockets.

SSE has a specified Content-Type of text/event-stream but you wouldn't have that header until the server already had given you a response. It may be possible to look at what the request accepts and upgrade it based on that header, but it seems like somewhat of a specialized case.

@jimjaeger
Copy link

Any outlook for a fix or is a workaround available?

@rstudner
Copy link

Curious if anyone has gotten SSE events to work through the proxy?

I have a UI, hitting this proxy, over to a nodejs server wanting to do SSE.

In production/no proxy/using just nginx everything works great. But in my dev environment, trying to use this proxy, it never seems to let the events "get to the browser" (server 100% pushes them out etc).

and on the UI side, the sse connection resets every 2 minutes (which also doesn't happen in an environment not using this proxy

@thomas-hilaire
Copy link

I tried with the timeout: 0 option but I have exactly the same issue than @rstudner
Note that I continue to get the connection:close header in the devtools, the timeout option does it job?

@aaronmaturen
Copy link
Contributor

I've been using this proxy with SSE for about the last year, there's an example at examples/http/sse.js that you can start and then go to http://127.0.0.1:8003 to see it being proxied with all the events every 1500ms.

If I change the proxy to have a timeout of 1000ms I see the initial :ok but then no results from the target server... but I'd expect that with the timeout being shorter than the event interval.

Could either of you provide a modified version of the sse example that doesn't send back responses so we can try to figure out what's going wrong?

@thomas-hilaire
Copy link

I finally found what was the issue. It comes from the https://webpack.js.org/configuration/dev-server/#devserver-compress option that was enabled. I used the compress: false option but I didn't noticed that the --compress flag was passed in the command-line.

It is now working, thx! 👍

@tiagocoutinho
Copy link

I' ve been fighting with this one for the last couple of days. Setting compress: false solved the problem for me. Thanks @thomas-hilaire!

@shijunti19
Copy link

shijunti19 commented Dec 12, 2018

I can't solve it. I'm nginx agent webpack vue2

@joshiste
Copy link

I guess this describes the culprit with the compression: https://github.com/expressjs/compression#server-sent-events

Is there a way to eagerly flush the response after each chunk recieved?

@han3zeng
Copy link

I use create-react-app to develop a project. Since it has a pre-configured webpack-dev-server, I create a node server to run SSE on both production and development mode.

In dev mode, the node server run as proxy server for the wepack-dev-server to handle SSE.
In production mode, the node server use to serve the static page(build) and handle SSE.

So my problem is that, sse works fine in production mode. However, in dev mode, sse fail to work. The node server do send the sse message, but the front page can not receive the response. Chrome console will show up such error because of timeout: net::ERR_INCOMPLETE_CHUNKED_ENCODING 200 (OK)

But once I modify the compress option in webpackDevServer.config file to false, everything works fine.

Thanks for the tip from @thomas-hilaire, it works.

@mihaigaita
Copy link

In case you're using React and Create React App (CRA) and don't want to eject to maintain your separate webpack config just to add the compress: false option, you can pass the 'no transform' option in the Cache-Control header of your backend route for the Server Sent Event.

Found out about this from another issue in CRA "If you can send a Cache-Control header with no-transform, you can avoid compression."

@ArkadiuszNiemiec
Copy link

ArkadiuszNiemiec commented Sep 17, 2020

I have just spend few hours figuring why my SSE not working in React App. The reason was that I was running development environment that uses setupProxy.js:

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(createProxyMiddleware("/api", { target: "http://localhost:4031/" }));
};

Running the exactly same code with nginx proxy works perfectly. Is there a way to debug it?

Here are ouputs of curl -v to a backend directly:

*   Trying 127.0.0.1:4031...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 4031 (#0)
> GET /api/uav/sim_000002/position/stream HTTP/1.1
> Host: localhost:4031
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Access-Control-Allow-Origin: *
< Cache-Control: no-cache
< Connection: keep-alive
< Content-Type: text/event-stream
< X-Accel-Buffering: no
< Date: Thu, 17 Sep 2020 22:34:54 GMT
< Transfer-Encoding: chunked

...and to the proxy:

*   Trying 127.0.0.1:3000...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 3000 (#0)
> GET /api/uav/sim_000002/position/stream HTTP/1.1
> Host: localhost:3000
> User-Agent: curl/7.68.0
> Accept: */*
>
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< X-Powered-By: Express
< access-control-allow-origin: *
< cache-control: no-cache
< content-type: text/event-stream
< x-accel-buffering: no
< date: Thu, 17 Sep 2020 22:44:48 GMT
< connection: close
< transfer-encoding: chunked
< Vary: Accept-Encoding

@seanmadi
Copy link

seanmadi commented Dec 15, 2022

Posting my solution here, since this is the first result I got from Google when dealing getting the same error.

I was getting net::ERR_INCOMPLETE_CHUNKED_ENCODING for several js files when trying to run NextJS through http-proxy in order to use HTTPS on NextJS. The way I solved the issue was by adding agent: http.globalAgent to createServer

proxy
	.createServer({
		xfwd: true,
		ws: true,
		target: {
			host: 'domain.com,
			port: 3001,
		},
		agent: http.globalAgent,
		ssl: {
			key: fs.readFileSync(key, 'utf8'),
			cert: fs.readFileSync(cert, 'utf8'),
		},
	})

@abcd-ca
Copy link

abcd-ca commented Feb 24, 2023

My server-sent events are working except my expressjs back-end is not receiving the close event from the client so my SSE connections are piling up on the server with every page reload. I'm not using Webpack, I'm using Vite and the Cache-Control: no-transform header is already there. Like others, this is only an issue with Vite's dev server, not with the production build. Demo and some other info referenced in this issue

Has anyone gotten this combination to work?

@MajedMuhammad
Copy link

The problem lies in the proxy server not listening to close events emitted from the client. After closing the connection by the client i.e., sse.close(), the connection is closed between the proxy and the client, but the proxy keeps the connection open to the server.

Any workaround is much appreciated.

@MajedMuhammad
Copy link

MajedMuhammad commented Jun 20, 2023

I found a workaround.

This is what I was trying to do for a few days and it is not working at all:

proxy.on("proxyReq", (req) => {
    req.on("close", () => {
        proxy.destroy();
    });
});

It will never work due to the first parameter is just the Client Request, not the actual streaming request.
It works if three parameters are passed:

proxy.on("proxyReq", (proxyReq, req, res) => {
    res.on("close", () => {
        if (!res.writableEnded) { # This if statement to check if the server still writing
            proxyReq.destroy();
        }
    });
});

Thanks to @sapphi-red & @chimurai.

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

No branches or pull requests