סליחה על ההפסקה הארוכה, טוב מאוחר מלא כלום...
ראשית לפני ההמשך, במידה ואתם לא יודעים JavaScript, אנא למדו אותה! המדריך הנוכחי הוא לא דרך ללמוד את השפה. בואו למדריך הזה עם ידע מספיק בJS בשביל לכתוב ממש קוד של עשרות שורות. ולא הביישן למד: תרגישו בנח לבקש עזרה אפילו "תת-רמה" בשאלות בפורום. פתחו ניק חדש למקרה של "בושות". כמו"כ כל פיסת קוד פה שאתם לא מבינים מזוית השפה, אסור לכם לחכות, זה לא יובהר בהמשך המדריך בשום צורה.. ת-ש-א-ל-ו! (או תחפשו באינטרנט מצידי).
הקדמה לשיעור 6, ארכיטקטורה של טפסי HTML וקצת על נוד.
תקציר וריענון
קודם כל לקלות המצטרפים אנחנו אוחזים בשלב של קובץ בודד בשם app.js שמכיל את הקוד הבא:
const http = require('http');
var list = [];
function handleAllRequest(req, res) {
res.setHeader('Content-Type', 'text/html');
if (req.url == '/')
res.write('Hello To List Page!');
else if (req.url == '/add-item')
res.write(`<form method="POST">
Enter the item value: <input type="text" name="the-name" >
<br>
<input type="submit" >
</form>`);
else
res.write('Opss... Not Found!');
res.end();
}
var server = http.createServer(handleAllRequest);
server.listen(3000);
בעת הרצה של קובץ זה בF5 בVSCODE, אפשר להיכנס לכתובות הבאות:
http://localhost:3000/ - רואים כיתוב Hello To List Page!
http://localhost:3000/add-item - רואים טופס ובו שדה בודד, עם לחצן שליחת נתונים. משום מה הכיתוב הוא באנגלית, אולי נגיע להסביר למה. בהמשך הכל יהיה עברית טהורה, אל דאגה!
הטופס הוא מסוג POST שהוסבר לעיל: מתודת POST פונה לכתובת (URL) אבל עם "מסוגלות" לשלוח נתונים בגוף הבקשה, קרי לא בURL. משמעות הצורה היא: נפח בקשה גדול, שיש מוסכמה שאופי הבקשה היא ביצוע פעולה (הדפדפן יתריע במקרה של ריענון, וגם לא ישמור את ה"ביקור" בהיסטוריה).
השליחה לא עושה משהו בינתיים.
וכמו תמיד, שוב הקדמת חובה מייגעת של דברים שכבר נאמרו...
כאמור בהודעה האחרונה בטופס HTML יש שני דרכי שליחה POST וגם GET, אבל שניהם עושים כמעט אותו דבר.
הם לוקחים את ערכי הקלט ואת שמותיהם בהתאמה בפורמט הבא:
שם-שדה-ראשון=ערך&שם-שדה-שני=ערך2&שם-אחר=ערך3&גיל=15
ושולחים אותם לשרת (לכתובת שנבחרה בaction ואם לא נבחרה כזו אז לכתובת הנוכחית).
איך שולחים? רק פה ההבדל במתודה. בGET, זה נוסף לנתיב, כלומר הכתובת כולה נראית למשל ככה:
http://site.com/some-path/add-product?name=camera&value=50
כלומר התוכן מצורף לכתובת אחרי סימן שאלה שמפריד בין הכתובת לבין ערכי בקשת הGET בפורמט האמור.
במתודת POST הכתובת נשארת http://site.com/some-path/add-product בלבד ללא כל תוספת, אבל בגוף הבקשה נוכל לראות* את התוכן הזה שם-שדה-ראשון=ערך&שם-אחר=ערך2&גיל=15 בלי סימן שאלה מקדים.
*איך? אפשר למשל בדפדפן בכלי הפיתוח, בלשונית Network בבחירת בקשת POST בכרטסת Headers למטה תחת Form Data או Palyload.
הערה: שני הקטעים הבאים, הם רשות. לא מזיק בכלל לקרוא אותם..., אבל אפשר להתעייף ולעבור לשיעור 6 - טפסי HTML, צד שרת
גוף בקשת הPOST
הוא תיאורטית ארוך...
המונח גוף הבקשה נקרא בשפת המקצוע body, או גם payload.
הוא בעצם כל תוכן הבקשה, החל מאחרי הכותרות שכמה שקובע איפה נגמר הכותרות זה שורה ריקה.
אין הגבלה עקרונית לגודל בקשה (מעשית יש ברוב המקרים וגם מצד הפרקטיקה), ממילא הPOST מסוגל להעביר הרבה מידע לשרת, בשונה ממתודת GET ששם זה הכתובת עצמה שיש לה הגבלות רשמיות כאלו ואחרות.
למה כל זה משנה כעת? כי כשבאים בnode לחפש את הbody של בקשה (כפי שעשינו במקרה של הurl) לא תמצאו אותו במאפיינים של הreq. למה? כי הוא אפילו לא הגיע לשרת. כלומר מייד כשמתחילה להגיע בקשה, הnode מטפל זה (וזה קורה מהר! כשברקע גוף הבקשה ממשיך להיטען). במידה ונדרש גם תוכן הבקשה, יש לבקש מנוד "להודיע" כשזה ייגמר, ואז להיכנס לפעולה.
"אתה יכול לקרוא לי כשגמרת?" callback ואירועים - Events
הבקשה הזאת לבקש מנוד ש"יודיע" כשהבקשה סיימה להתקבל, נקראת (בעולם התכנות) ל"הירשם לאירוע". כשקורה האירוע - במקרה שלנו סיום קבלת הבקשה מהלקוח, כל מי שהיה "רשום" לקבל הודעה מקבל אותה. צורת הרישום כבר מוכרת לנו, השתמשנו בה בhttp.createServer. סיפקנו שמה בסוגריים של פונקציה שיש להפעיל כאשר קורה אירוע של בקשה חדשה.
צורת ההירשמות הזו של http.createServer נקראת callback, משמעות המילה הזו מקפלת בתוכה call back (קריאה בחזרה): "כשתגמור את מה שאני אומר לך עכשיו, חזור וקרא לX". זה בפועל מממש את רעיון האירוע כי אפשר ככה ל"הירשם" לכל אירוע ע"י שמספקים למי (במקרה שלנו מודול הhttp של נוד) שיודע מתי שיקרה משהו (במקרה שלנו בקשה אינטרנט חדשה) שיודיע לנו - יפעיל את הפונקציה שסיפקנו.
הערה: בדרך כלל callback לא בא לממש את רעיון אירוע שרעיונית הוא רב פעמי (כל פעם שקורא בקשה תפעיל את X), אלא את רעיון המשכיות של פקודה (כשאתה גומר את זה תעשה את זה). ברוב שפות התכנות כשיש שתי שורות קוד, השניה תקרה תמיד אחרי שהראשונה תסיים לחלוטין וגם בJavaScript זה ככה, אולם בJavaScript כל פקודה שקשורה לקלט פלט (קבצים רשת ועוד) היא מסתיימת כביכול מיידית, בחינת "שגר ושכח", אבל עם callback - קרי "מה לעשות כשאני באמת אגמור". אם רוצים שהשורה שלאחריה תקרה רק בסיומה הרי שיש להעבירה לcallback ולא לשים אותה סתם שורה אחריה.
התכונה הזו של נוד שכל דבר שלוקחת זמן יש "להירשם" כדי לבצע דברים בעקבות סיומה, היא מעצבנת הרבה מפתחים שבאים ממחוזות בעלי השקפה שונה, אולם היא עיקר המעלה של נוד בביצועים, והביצועים של נוד הם מדהימים בעיקר במובן הזה. כך שמאוד כדאי לכוף את האזן ולשמוע ולהתרגל עד ש... נהנים.
נוד, וספריות
הקדמה: בין מי שמכיר את נוד, בין מי שלא, וקל וחומר מי שמגיע ממחוזות אחרים, יכול לתהות:
- למה דברים כ"כ פשוטים צריכים כ"כ הרבה קוד וסיבוך?
- למי שמגיע ממחוזות דוטנט או PHP , לכשיראה בהמשך שנעבוד עם ספריות תעלה השאלה - איך במדריך "לפי הספר" של א' ב' של סביבה, נכנסים ספריות? הרי זו התחלה על רגל שמאל לכל סביבה שמכבדת את עצמה שכבר במדריך הראשוני, בGet-Started מדברים על פלאגין/הרחבה שמשמעותם שהסביבה "שכחה" יכולת זו או שהיא שולית בצורך הפיתוח.
- למי שמכיר את נוד הנוסח הוא: למה הוא לא משתמש בexpress או בXYZ וכו'?
התשובה על 1+2 היא: נוד זה ליבה כה רזה, שאי אפשר לפתח בה משהו אמיתי בלי ספריות.
למה עשו כזה דבר? כי זה הדרך המודרנית בסביבות עבודה ובפרט בקוד פתוח, לעשות הפרדה כלל היותר בין רכיבים ולהימנע ממטריה כוללת של all in one שיש בה כמה נזקים. דמיינו שאנחנו חייבים לקנות את העוף לשבת ואת הסלטים מאותה חברה/חנות.
א. אנחנו נתפשר באחד מהם כי אין לנו יכולת להפריד ולקחת את החנות הטובה לכל אחד מהם, ב. וגם החנות תידרש להיות טובה רק באחד מהם, כי הרי השני כבר "מחוייב". ג. אם אחד ממש יפריע לנו נעזוב את החנות למרות שהשני הוא הכי טוב/זול/מתאים לנו דוקא שמה. ד. היכולת של החברה/חנות להיות טובה יותר בשני תחומים נופלת בהרבה מהיכולת להיות הכי טובים/זולים/מתאימים בתחום אחד
שימו לב למילים "מתאים לנו", כי כמו שבאוכל כל אחד מבין שגם ברמה התיאורטית אין הכל "הכי טוב", שהרי יש מי שמתאים לו ככה ויש אחרת, ככה ויותר זה גם בפיתוח. למרות שיש דרישות נורמליות של רוב היישומים בצרכים, זה רחוק מלהיות אמיתי לכל מקרה. כלומר תמיד יש צורך בהתאמות או בהתנהגות שהיא היפך הצורך הרגיל, ממילא גם אם מתכנתי סביבה הם מלאכים, הרי בשביל שהמוצר שלהם יתאים לכולם תמיד הם צריכים לפתח מאה אלטרנטיבות והגדות לכל יכולת.
לכן כל סביבת עבודה חדשה שמפתחים היום (למעט סביבות שבאות לטפל בחלק שולי או נקודתי של מערכת) נזהרת בעניין הזה - א. לתת חופש מלא למפתח להשתמש לצרכים אחרים בדברים אחרים, ב. להתמקד בנושא אחד ולא להתפזר.
אז אם ככה דרך המלך להשתמש טוב בנוד זה לחבר אליה אליה ספריות מובילות של נושא שאני זקוק לו לפי ההתאמה אלי. מכאן אנו עוברים לשאלה 3, למה אני לא משתמש במדריך פה בספריות, הרי זה לא שייך ככה לכתוב אפליקציה.
התשובה על שאלה 3 כבר נאמרה ברמזים כאלה או אחרים בעבר: המדריך פה אינו לנוד, אלא לפיתוח אינטרנט. כל הסיבה שבחרתי בנוד זה כדי לעקוב אחרי הצרכים ב"קיצורים" וספריות. לראות איפה צריך אותם ובעיקר מה הם עושים, שהשימוש בהם לא יהיה "קסם" שגורם לתלות ולערפל גמור בנבכי העניין אלא כלי שמבינים עם מה הוא מתמודד ומה יכולותיו ותו לא.
אנחנו ממש קרובים לשלב שבו נעבור לשימוש בספריות מפורסמות שיקלו את החיים באופן דרמטי.