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

Fix: Prevent 'can't find the internet' flash on reload (Firefox) #5735

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

ftes
Copy link
Contributor

@ftes ftes commented Feb 29, 2024

Note: This bug is LiveView-specific. However, it seems necessary to apply the fix in phoenix.

On page reloads and browser back navigation I and others see the phx-disconnected flash error briefly pop up in Firefox.

This change fixes the problem. It might not be a good fix, I'm unsure if there are other adverse effects.
It relies on the error code 1001 to detect this special situation in firefox, similar to this removed code in LiveVIew.

Chain of events in Firefox:

  1. full page reload triggered
  2. phoenix/socket.js -> onConnClose
  3. phoenix/socket.js -> triggerChanError -> channel.trigger('phx_error')
  4. `phoenix_live_view/view.js -> onError

Note the diff between the logs (obtained via new LiveSocket(... { logger: console.log }):
Firefox logs transport close, close { code: 1001 }, channel error where chrome doesn't.

console log (firefox)
Navigated to http://localhost:4000/projects/1/dashboard
transport close 
close { target: WebSocket, isTrusted: true, wasClean: true, code: 1001, reason: "", srcElement: WebSocket, currentTarget: WebSocket, eventPhase: 2, bubbles: false, cancelable: false,}
new_app.js:5139:27
channel error lv:phx-F7hLjZ6Il7DkWAwC undefined new_app.js:5139:27
channel error lv:phx-F7hLjZ13xdjkWAvC undefined new_app.js:5139:27
channel error inactivity:f60a20f8-2b63-481f-9595-3343e4d19f27 undefined new_app.js:5139:27
push lv:phx-F7hLjpQdIV0tfw3C phx_join (4, 4) 
Object { redirect: undefined, url: "http://localhost:4000/projects/1/dashboard", params: {}, session: "SFMyNTY.g2gDaAJhBXQAAAAIZAACaWRtAAAAFHBoeC1GN2hManBRZElWMHRmdzNDZAAMbGl2ZV9zZXNzaW9uaAJkAAdwcm9qZWN0bggAwnPYATFFuBdkAApwYXJlbnRfcGlkZAADbmlsZAAIcm9vdF9waWRkAANuaWxkAAlyb290X3ZpZXdkABhFbGl4aXIuRXYyV2ViLkhlYWRlckxpdmVkAAZyb3V0ZXJkAANuaWxkAAdzZXNzaW9udAAAAAFtAAAABmRlc2lnbmQAA25ld2QABHZpZXdkABhFbGl4aXIuRXYyV2ViLkhlYWRlckxpdmVuBgB8DjX0jQFiAAFRgA.UjIWWQ6LRej84SASE82AIIwUh7n11ZPcXigq4wbV4sM", static: "SFMyNTY.g2gDaAJhBXQAAAADZAAKYXNzaWduX25ld2pkAAVmbGFzaHQAAAAAZAACaWRtAAAAFHBoeC1GN2hManBRZElWMHRmdzNDbgYAfA419I0BYgABUYA.8C_d3_zFFaF7nbcpwXkef1bKefydfK-U7OcisSiAupU", flash: undefined }
socket.js:267:44
push lv:phx-F7hLjpMgWJktfxFB phx_join (7, 7) 
Object { redirect: undefined, url: "http://localhost:4000/projects/1/dashboard", params: {}, session: "SFMyNTY.g2gDaAJhBXQAAAAIZAACaWRtAAAAFHBoeC1GN2hManBNZ1dKa3RmeEZCZAAMbGl2ZV9zZXNzaW9uaAJkAAdwcm9qZWN0bggAwnPYATFFuBdkAApwYXJlbnRfcGlkZAADbmlsZAAIcm9vdF9waWRkAANuaWxkAAlyb290X3ZpZXdkAB5FbGl4aXIuRXYyV2ViLlByb2plY3RMaXZlLlNob3dkAAZyb3V0ZXJkABRFbGl4aXIuRXYyV2ViLlJvdXRlcmQAB3Nlc3Npb250AAAAAGQABHZpZXdkAB5FbGl4aXIuRXYyV2ViLlByb2plY3RMaXZlLlNob3duBgB4DjX0jQFiAAFRgA.5K8Bq2EqV2ubiesr64iD6j7D4v2ouZx-R7DvFaBaFEA", static: "SFMyNTY.g2gDaAJhBXQAAAADZAAKYXNzaWduX25ld2wAAAACZAAHcHJvamVjdGQADGN1cnJlbnRfdXNlcmpkAAVmbGFzaHQAAAAAZAACaWRtAAAAFHBoeC1GN2hManBNZ1dKa3RmeEZCbgYAeA419I0BYgABUYA.jZj333posK4vNG2Hx7m-ZLo0p4V2MsdInT_yQhvF5jM", flash: undefined }
socket.js:267:44
push inactivity:f60a20f8-2b63-481f-9595-3343e4d19f27 phx_join (15, 15) 
Object {  }
socket.js:267:44
transport WebSocket connected to ws://localhost:4000/live/websocket?_csrf_token=PAEaNQ8CJUgDAhw0CixuXRQlUSMvHwAQ_HIGYmHxucdumf6nnBeaIG_u&_mounts=0&_live_referer=undefined&vsn=2.0.0 undefined socket.js:267:44
receive ok lv:phx-F7hLjpQdIV0tfw3C phx_reply (4) 
Object { response: {}, status: "ok" }
socket.js:267:44
receive ok lv:phx-F7hLjpMgWJktfxFB phx_reply (7) 
Object { response: {}, status: "ok" }
socket.js:267:44
receive ok inactivity:f60a20f8-2b63-481f-9595-3343e4d19f27 phx_reply (15) 
Object { response: {}, status: "ok" }
socket.js:267:44
receive  inactivity:f60a20f8-2b63-481f-9595-3343e4d19f27 set-timeout  
Object { timeout: 28800 }
socket.js:267:44
push lv:phx-F7hLjpMgWJktfxFB event (7, 16) 
Object { type: null, event: "lv:clear-flash", value: {} }
socket.js:267:44
receive ok lv:phx-F7hLjpMgWJktfxFB phx_reply (16) 
Object { response: {}, status: "ok" }
socket.js:267:44
console log (chrome)
Navigated to http://localhost:4000/projects/1/dashboard
socket.js:267 push lv:phx-F7hLtKjOqrzsmAqD phx_join (4, 4) {redirect: undefined, url: 'http://localhost:4000/projects/1/dashboard', params: {}, session: 'SFMyNTY.g2gDaAJhBXQAAAAIZAACaWRtAAAAFHBoeC1GN2hMdE…AFRgA.9gCXRq_L3GGDyscxmXd3qlOs5Wx2IAY9A8Za6bu7mms', static: 'SFMyNTY.g2gDaAJhBXQAAAADZAAKYXNzaWduX25ld2pkAAVmbG…ABUYA.Z368HoKKH0kFi_c9cjqJgYQY2G7wJCSN6d7DiAOiYC8', …}
socket.js:267 push lv:phx-F7hLtKfxppjsmBgB phx_join (7, 7) {redirect: undefined, url: 'http://localhost:4000/projects/1/dashboard', params: {}, session: 'SFMyNTY.g2gDaAJhBXQAAAAIZAACaWRtAAAAFHBoeC1GN2hMdE…AFRgA.LgBBbUrXGIZ1HCYdYKCDFsAb_E3I_iBJLk68mj2VKwc', static: 'SFMyNTY.g2gDaAJhBXQAAAADZAAKYXNzaWduX25ld2wAAAACZA…ABUYA.90j5VwPgWuZmMPEMGGuR9czBArZKCVDvek1yVzsEYaY', …}
socket.js:267 push inactivity:7fc08fc7-8c05-4179-91e3-fb9c6567cf58 phx_join (15, 15) {}
socket.js:267 transport WebSocket connected to ws://localhost:4000/live/websocket?_csrf_token=Ixw3IB5hYH9bUQodLHJLLgsnUC5GHyg6dVCLfUW046IvC3-EOqag3www&_mounts=0&_live_referer=undefined&vsn=2.0.0 undefined
socket.js:267 receive ok lv:phx-F7hLtKjOqrzsmAqD phx_reply (4) {response: {}, status: 'ok'}
socket.js:267 receive ok lv:phx-F7hLtKfxppjsmBgB phx_reply (7) {response: {}, status: 'ok'}
socket.js:267 receive ok inactivity:7fc08fc7-8c05-4179-91e3-fb9c6567cf58 phx_reply (15) {response: {}, status: 'ok'}
socket.js:267 receive  inactivity:7fc08fc7-8c05-4179-91e3-fb9c6567cf58 set-timeout  {timeout: 28800}
socket.js:267 push lv:phx-F7hLtKfxppjsmBgB event (7, 16) {type: null, event: 'lv:clear-flash', value: {}}
socket.js:267 receive ok lv:phx-F7hLtKfxppjsmBgB phx_reply (16) {response: {}, status: 'ok'}

See

@SteffenDE
Copy link
Contributor

I didn't dig very deep, so I just put this as a question here: could this have any effects for servers sending 1001, e.g. when caddy reloads its config?
See phoenixframework/phoenix_live_view#2544

@deepfryed
Copy link

@ftes should it also include 1000 which would be normal close on page reload or navigate ? https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code

@ftes
Copy link
Contributor Author

ftes commented Jun 14, 2024

should it also include 1000 which would be normal close on page reload or navigate ? https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code

I haven't observed errors for close code 1000, so I don't think it's strictly necessary.
But I don't have a good enough understanding of the LiveView client side teardown process to say for sure.

@deepfryed
Copy link

FWIW I've had to override it in my LV app with 1000 to stop seeing the connection lost alerts on firefox

class PhoenixSocket extends Socket {
  onConnClose = function(event) {
    let closeCode = event && event.code
    if(this.hasLogger()) this.log("transport", "close", event)
    if (closeCode == 1000 || closeCode == 1001) this.channels.forEach(c => c.leave())
    this.triggerChanError()
    this.clearHeartbeats()
    if(!this.closeWasClean && closeCode !== 1000){
      this.reconnectTimer.scheduleTimeout()
    }
    this.stateChangeCallbacks.close.forEach(([, callback]) => callback(event))
  }
}

let liveSocket = new LiveSocket('/live', PhoenixSocket, { ...

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

Successfully merging this pull request may close these issues.

3 participants