Post
2025年10月21日 下午12:11

GraphQL 的核心設計理念圍繞著結構化資料的查詢與變更 (query and mutation)。它的請求和回應都是基於 JSON 這類的文字格式。傳統上,GraphQL 請求透過 HTTP POST 方法,將一個 JSON 物件作為請求主體 (request body) 發送到伺服器。這個 JSON 物件包含了查詢字串 (query string)、變數 (variables) 和操作名稱 (operation name)。

然而,檔案,特別是二進位檔案,本質上並非 JSON 這類結構化的文字資料。直接將二進位檔案嵌入 JSON 中,不僅會造成龐大的效能開銷(舉例來說,將檔案編碼成 Base64 字串會額外增加約 33% 的資料量),而且對伺服器的解析與處理也極為不便。

因此,GraphQL 規範本身並沒有提供直接處理檔案上傳的內建機制。開發者通常需要仰賴現有的 HTTP 機制或其他協定,來補足這方面的功能。

當我們在開發 Mosir 的中期,選擇了由社群發展出的一套基於 HTTP multipart/form-data 的方案,即 GraphQL Multipart Request Specification。

其核心概念是將傳統的 application/json Content Type 轉換為 multipart/form-data。一個典型的 multipart/form-data 請求會包含以下幾個部分:

- operations 部分: 包含常規的 GraphQL Query 或 Mutation,其中檔案變數會以 null 或特定的佔位符號表示。

  • map 部分: 定義 operati...
...顯示更多 (735 字)

在開發中後期遇到 multipart/form-data 的問題時,在評估後我們選擇改用 TUS (The Upload Server)。TUS 是一個開放的、獨立於 GraphQL 的協定,專為可靠的、可恢復的檔案上傳而設計。它的核心理念,就是將大型檔案拆分成可管理的區塊,並提供斷點續傳的能力。

TUS 在 GraphQL 架構中的角色並非直接融入 GraphQL 的請求處理,而是作為一個外部的、專門的檔案上傳服務,而 GraphQL API 則扮演協調者 (Coordinator) 的角色,尤其在檔案完成上傳後處理業務邏輯方面。

第一步:Client 與 TUS 伺服器互動 (HTTP P...

...顯示更多 (865 字)

TUS 架構的顯著優勢:

  • 徹底解決斷點續傳問題: TUS 從協定層面支援斷點續傳,即使面對不穩定的網路或大型檔案,也能提供無縫、可靠的上傳體驗,讓使用者可以從上次中斷的地方繼續上傳。

  • 提升 Proxy 效能與可擴充性: 當客戶端直接與 TUS 伺服器互動時,大型檔案的上傳流量不再經過主 GraphQL API 的代理,這能大幅減輕反向代理 (Reverse Proxy) 和 API Gateway 的負擔,避免因緩衝大型檔案而承受壓力。同時,TUS 伺服器可以獨立於 GraphQL 服務進行擴充,若檔案上傳需求大增,可專門擴充 TUS 服務叢集而不影響 GraphQL 服務效能。此外,TUS 服務可部署在更靠近使用者端點的地區,或利用專門為檔案上傳優化的基礎設施,從而提供更快的上傳速度。

  • 降低 GraphQL 服務壓力與職責分離: GraphQL 服務能專注於其核心職責——處理資料的查詢與變更。繁重的檔案 I/O 操作則交由專門的 TUS 服務高效處理,這種職責的分離使得 GraphQL 服務更加輕量、高效且更容易維護。

  • 精細的進度回報: 由於 TUS 採用分塊上傳機制,TUS 客戶端函式庫能提供精確的即時上傳進度資訊,大幅改善了大型檔案上傳過程中的使用者體驗。
相關留言

用過 Go + gqlgen 和 Node.js + TypeORM,反而覺得 GraphQL 被捧的太高了。沒有解決問題,反而製造問題,例如:N+1 需要 Dataloader 處理、無法傳遞二進制…

Facebook 當初設計 GraphQL,是為了讓 Resolver 能從不同微服務整合資料,統一回傳給前端。但很多人把它當成 HTTP API 的替代方案使用,就像 JWT 被誤用為取代 Session 一樣。

開發速度遠不如一個 POST /upload_video API。但前端生態彷彿不用上新技術就會被淘汰。似乎懂得什麼該捨棄,比學會技術還難。

但我現在用 Go + HTMX 超快樂… 🫠