最近在撰寫前端透過 Websocket 傳輸檔案的系統時,發現後端 ( Java ) 每接收完一個檔案之後都會造成前端的 Reload ,無法連續傳送多個檔案,遇到這個問題時不太清楚為什麼會發生,以下列出我一開始嘗試的解決方法。
起初的解決方法
列出這些我嘗試過的方法,給大家一個參考,但這四點不是本文最主要的原因。
- WebSocket 後端寫檔時造成 Server Side Blocking ,前端重整(理論上不會)
- Server 的 Reveiver Buffer 不夠大
- Client 一次送出太大的 Packet
- 查看 Websocket Protocol 中 Reload 事件會在何時發生
檢查Server Side Blocking
在 Socket 通訊當中,Client 傳送一則訊息之後應該是不會等待Server 回應才對,但擔心是 Java Websocket 套件的關係,所以先嘗試解決 Blocking 的問題。
- 把寫檔丟入另一個 Thread
- 用上 Java Non-BlockingIO
最後結果不意外的失敗了,前端一樣重整。
Server 的 Reveiver Buffer 不夠大
由於主要傳送的檔案為影音檔案,一個檔案的大小約在900KB左右,算是比較大的單一檔案,所以我將Server Websocket的Buffer加到了16MB,但仍然前端重整。
Client 一次送出太大的 Packet
前兩點將 Server Side 有可能的問題大概都解決完了,接下來開始懷疑前端,前端有使用到 RecordRTC ,將 Client 的畫面每3秒錄製下來並傳送到 Server,在前一點提到了檔案約在 900 KB 左右,所以前端改為每 100 ms 傳送一次,檔案雖然變小但仍然會重整(此時有機率送出 2 ~ 4 次檔案)。
Websocket 的 Protocol 定義
到這一步我已經快黔驢技窮了,確認 Server 和 Client 都沒問題之後,透過Chrome的開發人員工具觀察到 Websocket 有送出 reload 的 event
因此就去查了一下 Websocket 的 reload event 會在何時發生,Websocket Protocol 定義在 RFC 6455 當中,稍微翻了一下內容,但內容並沒有寫到 reload event 定義 Orz…
問題所在
花了一整天的時間仍然無法解決,隔了 2 天之後才回來繼續解決這個問題,這次我將 Server 放在 A 電腦, Client 放在 B 電腦,並執行有之前仍然有問題的 Code,但是! 這次很順利的傳輸多個檔案了!!
這時 iftnt 提出了一個問題「你的後端寫檔位置是不是在LiveServer的路徑底下」
這時候想了一下,好像真的蠻有可能是 LiveServer 造成的問題, LiveServer 會監聽底下路徑的所有檔案,一旦有任何變動都會 Auto Refresh ( 包含存檔、新增檔案 ),而且 LiveServer 也是以 Websocket 來實作 Local Server ,原來是開發工具我發出來的 event阿……
大概的檔案結構如下
Server 會將前端傳過來的 webm 檔案存到前端的 ./uploads 資料夾底下,也就是 VSCode LiveServer 的作用範圍,造成 reload
最後將寫檔路徑換到非 Live Server 作用範圍底下之後就可以正常運作了。
結語
現在雖然許多開發工具相當好用,我也非常喜歡 Live Server 這個擴充元件,但若不了解其運作機制會造成的潛在風險的話,可能會遇到多個開發工具搭配下不可預期的例外狀況發生,雖然這次問題也算是我自己犯蠢,但也是分享出來給大家知道,使用 Live Server 時這裡會有的地雷要注意。