Menu

express.static: הגשת קבצים סטטיים ב-Express

app.use(express.static(path.join(__dirname, 'public'))) מגיש כל קובץ בתיקייה public ב-URL המתאים: public/style.css עונה ל-/style.css. הוסיפו mount path כדי להגיש אותם תחת prefix.

בדף הזה יש עורכים שאפשר להריץ. לערוך, להריץ ולראות את הפלט מיד.

express.static הוא ה-middleware המובנה שמגיש קבצים מתיקייה. app.use(express.static(path.join(__dirname, 'public'))) הופך כל קובץ ב-public לזמין באותו נתיב ב-URL: ‏public/style.css עונה ל-/style.css, ו-public/index.html עונה ל-/. Express מגדיר את ה-Content-Type לפי סיומת הקובץ, וכשאף קובץ לא תואם הוא מעביר את הבקשה ל-routes שלכם במקום לענות 404.

התשובה ל-GET /style.css היא הטקסט של הקובץ, עם Content-Type: text/css; charset=utf-8 בלשונית ה-Headers. שלחו GET / כדי לקבל את index.html, ואז GET /api/time: אין קובץ כזה, אז ה-route עונה.

למה נתיב התיקייה צריך את __dirname

express.static('public') מפענח את 'public' ביחס לתיקייה שממנה הפעלתם את Node, לא לתיקייה שבה נמצא server.js. זה עובד כשמריצים node server.js בתוך הפרויקט, ונשבר כשמנהל תהליכים או סקריפט מפעילים את האפליקציה ממקום אחר:

// project/server.js uses express.static('public')
// cd project && node server.js      -> serves project/public
// node project/server.js            -> looks for ./public, every file is 404

path.join(__dirname, 'public') היא התיקייה שליד הקובץ שמכיל את השורה, לא משנה מאיפה Node הופעל. ב-ES module השתמשו ב-path.join(import.meta.dirname, 'public') (‏Node 20.11 ומעלה). הדף על המודול path מכסה את __dirname ואת path.join בפירוט.

הגשת קבצים תחת prefix

העבירו mount path ראשון כדי להגיש את התיקייה תחת prefix ב-URL. ה-prefix הוא לא חלק מהנתיב של הקובץ בדיסק:

GET /assets/app.js מחזיר console.log("hi"); כ-text/javascript, ו-GET /assets/img/dot.svg מגיע לתיקיית המשנה. שלחו GET /app.js בלי ה-prefix: זה 404, כי הקבצים קיימים רק תחת /assets. השתמשו ב-prefix כדי שכתובות של קבצים לא יתנגשו ב-routes של ה-API שלכם.

headers של cache עם maxAge

כברירת מחדל Express שולח Cache-Control: public, max-age=0, כך שהדפדפנים בודקים מול השרת בכל שימוש (ומקבלים 304 Not Modified מהיר כשהקובץ לא השתנה, בזכות ה-header ‏ETag). לקבצים שהשמות שלהם משתנים בכל build, כמו app.3f9a1c.js, אמרו לדפדפנים לשמור אותם:

פתחו את לשונית ה-Headers: ‏Cache-Control הוא עכשיו public, max-age=604800, שבעה ימים בשניות. index: false מכבה את הגשת index.html עבור כתובות של תיקיות. אפשרויות שימושיות נוספות הן extensions: ['html'], שמאפשרת ל-/about למצוא את about.html, ו-dotfiles, שהיא 'ignore' כברירת מחדל, כך שקבצים כמו .env אף פעם לא מוגשים.

Single page apps: חזרה ל-index.html

אפליקציית React או Vue שבנויה לניתוב בצד הלקוח צריכה שכל נתיב לא מוכר יחזיר את index.html, כדי שרענון ב-/settings לא ייתן 404. שימו את ה-fallback אחרי express.static ואחרי ה-routes של ה-API:

app.use(express.static(path.join(__dirname, 'dist')));
app.use('/api', apiRouter);

// Express 5 wildcard syntax
app.get('/*splat', (req, res) => {
    res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});

טעויות נפוצות

לכלול את שם התיקייה ב-URL. עם app.use(express.static('public')) ה-URL הוא /style.css, לא /public/style.css. אם אתם רוצים /public ב-URL, חברו אותו כ-mount path: app.use('/public', express.static(...)).

קישור לקבצים עם נתיבים יחסיים ב-HTML. <link href="style.css"> בדף /blog/post מבקש את /blog/style.css. התחילו את הנתיב בלוכסן: /style.css.

לשים סודות בתיקייה הסטטית. כל מה שבתוכה ציבורי. השאירו קבצי הגדרות, מפתחות וקוד מקור מחוץ לה.

שאלות נפוצות

אפשר להשתמש ב-express.static יותר מפעם אחת?

כן. רשמו אחד לכל תיקייה; Express מחפש בהן לפי הסדר שבו הוספתם אותן ומגיש את הקובץ הראשון שהוא מוצא. תנו לכל אחד mount path משלו כשבתיקיות עשויים להיות קבצים עם אותו שם.

האם Express צריך להגיש קבצים סטטיים ב-production?

לאפליקציות קטנות זה בסדר. לתעבורה כבדה, שימו לפניו CDN או reverse proxy כמו Nginx, שמגישים קבצים מהר יותר ושומרים אותם ב-cache קרוב יותר למשתמשים, והשאירו את Express ל-API.

איך שולחים קובץ מסוים אחד מתוך route?

השתמשו ב-res.sendFile(path.join(__dirname, 'files', 'report.pdf')). הנתיב חייב להיות מוחלט (או שמעבירים אפשרות root). השתמשו ב-res.download() במקום כשהדפדפן צריך לשמור את הקובץ ולא להציג אותו.

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל