vitejs / vite

Next generation frontend tooling. It's fast!
http://vitejs.dev
MIT License
67.2k stars 6.04k forks source link

Client pinging behind a proxy unexpected reload on websocket disconnect #13125

Open jeoy opened 1 year ago

jeoy commented 1 year ago

Describe the bug

This issue was reported before in this issue https://github.com/vitejs/vite/issues/4501, and a fix was implemented in https://github.com/vitejs/vite/pull/5466.

However, this change reverted by https://github.com/vitejs/vite/pull/6819

When websocket behind a proxy is disconnected, the fetch request result is 4xx or 5xx , Fetch promises only reject with a TypeError when a network error occurs. Since 4xx and 5xx responses aren't network errors, there's nothing to catch. So the page reloads, but it cannot load because the proxy server is down.

Description ---- from issue https://github.com/vitejs/vite/pull/5466

When running the Vite dev server behind a proxy, the fetch request results in a 502 status code. This 502 does not throw an error, triggering the catch statement. Instead, the loop breaks (because of the break statement on the next line). When it breaks, the page reloads, but it cannot load because the proxy server is down. This causes those of us working behind proxies to lose frontend application state whenever the proxy restarts.

Reproduction

-

Steps to reproduce

No response

System Info

System:
    OS: macOS 12.6
    CPU: (12) x64 Intel(R) Core(TM) i7-9750H CPU @ 2.60GHz
    Memory: 182.34 MB / 16.00 GB
    Shell: 5.8.1 - /bin/zsh
  Binaries:
    Node: 16.14.0 - ~/.nvm/versions/node/v16.14.0/bin/node
    Yarn: 1.22.17 - ~/.nvm/versions/node/v16.14.0/bin/yarn
    npm: 8.3.1 - ~/.nvm/versions/node/v16.14.0/bin/npm
  Browsers:
    Chrome: 112.0.5615.137
    Firefox: 99.0.1
    Safari: 15.6.1
    Safari Technology Preview: 16.4
  npmPackages:
    @vitejs/plugin-vue: ^4.1.0 => 4.2.1 
    vite: ^4.3.2 => 4.3.5

Used Package Manager

pnpm

Logs

No response

Validations

bluwy commented 1 year ago

I'm not really sure how we can fix this. According to the comment which reverted the fix:

https://github.com/vitejs/vite/blob/535795a8286e4a9525acd2340e1d1d1adfd70acf/packages/vite/src/client/client.ts#L318-L319

A successful websocket ping would've return 400, which we would want to reload in that case. As a fix, maybe we can check for 400 only, or skip if it's a 502, or somehow check if a proxy server is running?

jeoy commented 1 year ago

@bluwy I believe there are two problems that need to be fix. Firstly, when using the no-cors mode in the fetch request, we are unable to receive any response or status,using the no-cors mode is not the ideal solution for resolving the CORS issue, as it can lead to other problems. There are alternative methods to handle CORS on the server-side that should be considered.

Then, we can get response and skip if pingResponse.ok === false, it's the best approach to resolve the issue. However, considering websocket 400 issue(pingResponse.ok is false but don't want reload) , we can work around this issue by skiping 5xx. Nevertheless, this workaround is not the optimal solution. A better approach would be to open an HTTP API on the same URL to state the WebSocket's status.

Ifthis proposal is feasible, I will open a PR later.

sun0day commented 1 year ago

I think the easy way is fetching the current location.href to see whether it's available

sapphi-red commented 1 year ago

I believe try opening WebSocket instead of pinging by a normal HTTP would be a better solution as it would be surely consistent. https://github.com/vitejs/vite/issues/5675#issuecomment-1345588419

towry commented 5 months ago

Client pings Server every 1s in case of connection-lost

This issue cause high cpu usage.