大家好! 🤗 如果你是後端開發新手,或者你已經掌握了一些基礎知識,但想更深入地了解伺服器背後的邏輯、請求路由以及所有這些基礎概念,我真心希望這篇文章能對你有所幫助。 🥰
一開始感到困惑或無法立即理解所有內容都是完全正常的,你最終會在適當的時機弄清楚!或許這篇文章能幫你解惑,或許只是印證了你已經知道的事情!
我們將討論以下概念:
路由是指當使用者存取特定URL (路徑或「路由」)時,決定傳回哪段程式碼或哪個頁面。這正是這兩個世界之間的第一個主要差異。
當我們使用現代前端框架(例如 React with Vite 或 Create React App)時,我們不需要處理靜態檔案的路由:
→開發伺服器很聰明:Vite 的開發伺服器旨在幫助我們快速編寫程式碼。它知道如何讀取我們的原始檔案( src/目錄下的檔案),並自動透過相應的 URL 提供這些檔案。
→自動路由:如果我們的 HTML 或 React 程式碼引用了/styles/main.css伺服器會立即知道在哪裡找到該檔案(在記憶體或檔案系統中),並立即將其傳送到瀏覽器。我們無需為此編寫任何特殊程式碼❗
→專注於應用邏輯:使用 React Router 等函式庫,我們只需專注於應用邏輯(例如,「如果 URL 為/profile ,則顯示 Profile 元件」)。路由操作在瀏覽器端進行,在 JavaScript 檔案載入完畢後完成。

Express.js 只是一個極簡框架。它沒有任何假設,也沒有任何內建的「魔法」。
→路由是手動的:一旦我們將 Express.js 設定為主伺服器,我們就必須明確地告訴它如何處理到達它的每個請求。
我們是否希望POST /api/login請求驗證資料庫中的密碼❓ 我們必須寫app.post('/api/login',...) 。
我們是否希望GET /api/users請求返回使用者清單❓ 我們必須寫app.get('/api/users', ...) 。
→靜態檔案辨識錯誤:如果沒有明確指示,當 Express 收到對/main.css的請求時,它無法辨識這是一個靜態檔案。它會尋找 API 路由或渲染邏輯。由於沒有找到,它會隱式回傳404 Not Found 錯誤。
在啟動時,Vite 開發伺服器會默默地執行一些神奇的操作,它會自動處理所有靜態檔案(如 CSS 和圖片)的路由和提供,直接從記憶體中讀取。
然而,當我們引入 Express.js 時,一切就變得複雜了。 Express 並不具備這種特性,它需要明確的指令。我們必須手動定義 API 路由(例如app.get('/api/data') ),更重要的是,我們必須使用express.static()手動告訴 Express:「這裡存放著網頁所需的所有靜態文件。」 如果沒有這一步,伺服器將無法存取我們的 CSS 和 JavaScript 文件,從而導致頁面無法正常顯示!
在開發過程中,當我們在 React 專案中執行npm run dev時:
→無實體資料夾:Vite 伺服器直接從src/目錄讀取檔案( .jsx 、 .css ),並將它們保存在 RAM(記憶體)中。它不會建立存放編譯文件的實體資料夾。
→速度:我們儲存的任何變更都會透過 HMR(熱模組重載)立即傳輸到瀏覽器,使編碼體驗流暢。
→尚未準備好投入生產:雖然速度很快,但這種模式並不穩定、不安全,也沒有針對網路上成千上萬的真實用戶進行最佳化。
何時以及為何需要編譯❓ 在發布應用程式(上線生產環境)之前,我們必須編譯程式碼:
→指令: npm run build 。
→優化:此命令獲取我們所有的來源檔案( React 、 CSS等),對其進行壓縮(使其體積更小),將其合併(將其放入更少的包中),並對其進行優化以獲得最大的加載速度。
→結果dist :所有這些最佳化後的檔案都會被放入一個新的實體資料夾中,通常名稱為dist或build 。此資料夾包含前端的最終靜態版本,隨時可以提供服務。
express.static() :→如何提供 dist 資料夾? ❓ 現在我們有了優化後的 dist 資料夾,我們必須告訴 Express(後端)它需要公開提供的資料夾:
→解決方案是使用express.static() :這行程式碼是我們給 Express 伺服器的指令:
// in production, Express serves the frontend's 'dist' folder
app.use(express.static(path.join(__dirname, 'client/dist')));
→如何運作:每當伺服器收到HTTP 請求,且該請求與我們定義的API 路由不符(例如,不以/api開頭)時,Express 都會在dist 資料夾中尋找!如果找到與請求 URL 相符的檔案(例如, /style.css ),它會立即將該檔案傳送給用戶端,並停止路由程序!
→ 如果我們在前端(React)和後端(Express)專案目錄中都看到了npm run dev指令,我們可能會認為它們的作用相同。但事實並非如此❗這是一個至關重要的區別,尤其是在考慮安全性和效能時。

→雙npm run dev :兩台伺服器,兩種用途
當我們談到開發模式(Dev)和生產模式(Prod)時,我們是在描述我們正在執行的程式碼的狀態和目的。
開發模式是我們的工作台,它針對速度和除錯進行了最佳化。
→目的:唯一目標是促進快速編碼、測試和除錯。
→前端設定:伺服器在一個連接埠(例如5173 )上執行Vite Dev Server 。
→後端工具:我們使用nodemon等工具,以便在儲存變更後立即自動重新啟動伺服器。
→錯誤:錯誤訊息會以醒目的方式詳細顯示(堆疊追蹤),並直接列印到您的控制台,幫助您立即解決問題。
→最佳化:檔案按原樣提供,優化程度極低,因為檔案大小和速度不是主要考慮因素。
生產模式是最終的、經過優化的版本,面向公眾發布,其設計注重穩定性和安全性。
→目的:目標是提供大眾穩定、快速、安全的體驗。
→前端設定:前端程式碼首先被建置(編譯和壓縮),然後由單一Express 伺服器在其指定連接埠(例如3000 )上提供服務。
→後端工具:我們使用高度最佳化的進程管理器(如 PM2)來保持伺服器持續穩定地運作。
→錯誤:錯誤訊息會在內部記錄,但絕不會向公眾使用者顯示,從而防止安全漏洞❗
→最佳化:檔案經過大量壓縮和積極緩存,以實現最佳效能,並為所有用戶提供更快的載入速度。
為什麼我們不在生產環境中執行開發模式❓
在執行中的公共伺服器上以開發模式執行 Express 伺服器是一個重大的安全漏洞,強烈不建議這樣做。
→安全漏洞:開發錯誤通常會洩漏敏感資料,例如伺服器上的檔案路徑、環境變數,甚至是資料庫結構的細節。將這些資訊洩漏給攻擊者是一個嚴重的安全漏洞❗
→效能:開發模式旨在提供便利,而非追求速度。在實際用戶負載下,您會遇到響應速度慢、資源管理不善以及可擴展性有限等問題。
→穩定性:像nodemon這樣的工具會在你儲存變更時重新啟動程式碼。對於需要 24/7 全天候執行的面向公眾的應用程式來說,這種行為不可預測且極不穩定❗
現在,讓我們來看看設定路由和中介軟體的關鍵流程,確保 Express 能夠正確處理所有請求。
在 Express 中,中間件就是一個在請求-回應週期中執行的函數。它可以存取請求物件req 、回應物件res以及週期中的next一個函數next 。
→ app.use(middleware) : 此方法主要用於註冊中間件。它會對所有HTTP方法( GET 、 POST等)和所有路徑(除非我們指定路徑前綴)執行提供的函數。
→黃金法則:中間件必須依照程式碼中定義的順序執行。一旦某個中間件發送了回應(例如, res.send('Hello') ),循環就會停止,後續的中間件或路由處理程序都不會執行❗
流程範例順序:
app.use(cors)
app.use(express.json)
app.use('/api', apiRouter)
app.use(express.static(dist_path)) <- 這是關鍵的分離點❗
……其他路線…
為什麼我們需要app.get('*') ❓這是將我們的後端邏輯與前端應用程式連接起來的最後一塊拼圖。
→用途: app.get('*')路由是通配符處理程序。它使用通配符*來匹配任何尚未被任何中間件或之前定義的路由處理的GET請求。
→場景:當使用者在瀏覽器中輸入類似mysite.com/profile直接連結時,伺服器會看到對/profile請求。
Express檢查API路由(例如/api )。未找到匹配項❗
Express 使用express.static()檢查是否存在名為 profile 的檔案。未找到匹配項。 ❗
該請求由app.get('*')處理。
→解決方案:我們告訴 Express 對於任何不匹配的路徑,直接提供主應用程式檔案( index.html )。
app.get('*', (req, res) => {
// we tell Express: "Send the HTML file and let React Router handle the URL."
res.sendFile(path.resolve(FRONTEND_BUILD_PATH, 'index.html'));
});
→結果:瀏覽器載入index.html ,React 接管,React Router 讀取/profile URL 並顯示正確的元件,從而實現流暢的單頁應用程式體驗❗
如果你是後端開發新手,一開始沒能理解這些概念,別灰心,它們一開始確實會讓人困惑。我想我們剛開始的時候都遇到過這些問題……我一定也遇到過! 🙃
主要挑戰在於我們需要轉變思維方式,從像 Vite 這樣的前端工具的自動記憶體服務,轉變為 Express更手動、更結構化的路由方法。
希望這篇文章對你有幫助,或是能讓你想起當初後端開發初期遇到的種種困難。 🤗
我很好奇有多少人一開始也經歷過同樣的困惑,如果你也覺得後端開發很難,請留言告訴我!我很想知道我不是唯一一個。 🤗🥰
祝您閱讀愉快!如果這篇文章對您有幫助或您覺得有用,請按個讚! 🤗
更多文章:
原文出處:https://dev.to/cristea_theodora_6200140b/frontend-to-backend-from-vite-to-express-2c83