מדריך קלאודפלייר בעברית

תיעוד 241

יצירת טופס HTML

עודכן לאחרונה ב-21 באפריל 2026. הצגה כ-Markdown | הגדרת סוכן

במדריך זה תיצרו <form> פשוט באמצעות HTML ו-CSS רגילים ותפרסו אותו ב-Cloudflare Pages. תוך כדי כך תלמדו על חלק ממאפייני טופס ה-HTML ועל איסוף הנתונים שנשלחו בתוך Worker.

סדרת מבוא של MDN

המדריך הזה נוגע בקצרה ביסודות של טפסי HTML. לסקירה מעמיקה יותר, פנו לסדרת המבוא של MDN: Web Forms , Working with user data.

המדריך הזה נשען במידה רבה על Cloudflare Pages ועל שילוב ה-Workers שלו. פנו למדריך Get started כדי להכיר את הפלטפורמה.

#סקירה

באינטרנט, טפסים הם נקודת אינטראקציה נפוצה בין המשתמש למסמך האינטרנט. הם מאפשרים למשתמש להזין נתונים, ובדרך כלל, לשלוח את הנתונים לשרת. טופס מורכב מלפחות קלט טופס אחד, שיכול להיות שדה טקסט, רשימה נפתחת, תיבת סימון ועוד.

לכל קלט צריך להיות שם, באמצעות המאפיין name, כדי שלערך הקלט יהיה שם מזוהה כשהשרת מקבל אותו. בנוסף, עם התקדמות HTML5, רכיבי טופס יכולים להצהיר על מאפיינים נוספים כדי להצטרף לאימות טופס אוטומטי. האימותים הזמינים משתנים לפי סוג הקלט. לדוגמה, קלט טקסט שמקבל כתובות דוא"ל (דרך type=email) יכול לוודא שהערך נראה כמו כתובת דוא"ל תקינה, קלט מספר (דרך type=number) יקבל רק מספרים שלמים או ערכים עשרוניים (אם מותר), וקלטי טקסט כלליים יכולים להגדיר pattern מותאם אישית שמותר. עם זאת, כל הקלטים יכולים להצהיר אם ערך הוא required או לא.

להלן דוגמה לטופס HTML5 עם כמה קלטים וכללי האימות שלהם:

<form method="POST" action="/api/submit">
	<input type="text" name="fullname" pattern="[A-Za-z]+" required />
	<input type="email" name="email" required />
	<input type="number" name="age" min="18" required />

	<button type="submit">Submit</button>
</form>

אם לטופס HTML5 מוגדרים כללי אימות, הדפדפנים בודקים אוטומטית את כל הכללים כשהמשתמש מנסה לשלוח את הטופס. אם יש שגיאות, השליחה נמנעת והדפדפן מציג למשתמש את הודעות השגיאה לתיקון. ה-<form> ישלח נתונים ב-POST לנקודת הקצה /submit רק כשאין שגיאות אימות פתוחות. כל התהליך הזה הוא חלק מובנה מ-HTML5 ודורש רק שמאפייני הטופס והקלט המתאימים יהיו קיימים: אין צורך ב-JavaScript.

לרכיבי טופס יכול להיות גם רכיב <label> שמשויך אליהם, וכך אפשר לתאר בבירור כל קלט. זה מועיל לבהירות חזותית, כמובן, וגם מאפשר חוויית משתמש נגישה יותר כי סימון ה-HTML מוגדר טוב יותר. טכנולוגיות מסייעות נהנות מכך ישירות. לדוגמה, קוראי מסך יכולים להכריז איזה <input> נמצא במוקד. וכשלוחצים על <label>, קלט הטופס שמשויך אליו מקבל את המוקד במקום זאת, וכך אזור ההפעלה של הקלט גדל.

כדי לאפשר זאת, צריך ליצור רכיב <label> לכל קלט ולהקצות לכל רכיב <input> ערך מאפיין id ייחודי. ל-<label> צריך להיות גם מאפיין for שמשקף את ערך ה-id הייחודי של הקלט שלו. עדכון הקטע הקודם אמור להניב את התוצאה הבאה:

<form method="POST" action="/api/submit">
	<label for="i-fullname">Full Name</label>
	<input
		id="i-fullname"
		type="text"
		name="fullname"
		pattern="[A-Za-z]+"
		required
	/>

	<label for="i-email">Email Address</label>
	<input id="i-email" type="email" name="email" required />

	<label for="i-age">Your Age</label>
	<input id="i-age" type="number" name="age" min="18" required />

	<button type="submit">Submit</button>
</form>

הערה

ערכי ה-for וה-id שלכם לא חייבים להתאים בדיוק לערכים שמוצגים למעלה. אפשר להשתמש בכל ערכי id, כל עוד הם ייחודיים במסמך ה-HTML. <label> יכול להיות מקושר ל-<input> רק אם מאפייני for ו-id תואמים.

כשה-<form> הזה נשלח עם נתונים תקינים, תוכן הנתונים שלו נשלח לשרת. אפשר להתאים אישית איך ולאן הנתונים נשלחים על ידי הצהרה על מאפיינים בטופס עצמו. אם לא מספקים את הפרטים האלה, ה-<form> ישלח את הנתונים ב-GET לכתובת ה-URL הנוכחית, וזה רק לעתים רחוקות ההתנהגות הרצויה. כדי לתקן זאת, לכל הפחות, צריך להגדיר מאפיין action עם כתובת ה-URL של היעד, אבל הצהרה על method מומלצת לעתים קרובות גם כן, גם אם מצהירים מחדש על ערך ברירת המחדל GET.

כברירת מחדל, טפסי HTML שולחים את התוכן שלהם בסוג ה-MIME application/x-www-form-urlencoded. הערך הזה ישתקף בכותרת ה-HTTP Content-Type, שהשרת המקבל חייב לקרוא כדי לקבוע איך לנתח את תוכן הנתונים. אפשר להתאים אישית את סוג ה-MIME דרך המאפיין enctype. לדוגמה, כדי לקבל קבצים (דרך type=file), צריך לשנות את enctype לערך multipart/form-data:

<form method="POST" action="/api/submit" enctype="multipart/form-data">
	<label for="i-fullname">Full Name</label>
	<input
		id="i-fullname"
		type="text"
		name="fullname"
		pattern="[A-Za-z]+"
		required
	/>

	<label for="i-email">Email Address</label>
	<input id="i-email" type="email" name="email" required />

	<label for="i-age">Your Age</label>
	<input id="i-age" type="number" name="age" min="18" required />

	<label for="i-avatar">Profile Picture</label>
	<input id="i-avatar" type="file" name="avatar" required />

	<button type="submit">Submit</button>
</form>

מכיוון ש-enctype השתנה, הדפדפן משנה גם את האופן שבו הוא שולח נתונים לשרת. כותרת ה-HTTP Content-Type תשקף את הגישה החדשה, וגוף בקשת ה-HTTP יתאים לסוג ה-MIME החדש. השרת המקבל חייב להתאים את עצמו לפורמט החדש ולהתאים את שיטת ניתוח הבקשה שלו.

#דוגמה חיה

שאר המדריך יתמקד בבניית טופס HTML ב-Pages, כולל Worker שיקבל וינתח את שליחות הטופס.

מאגר GitHub

קוד המקור של הדוגמה הזו זמין ב-GitHub. זו אפליקציית Pages חיה, עם הדגמה חיה זמינה גם כן.

#הקמה

כדי להתחיל, צרו מאגר GitHub חדש. אחר כך צרו ספרייה מקומית חדשה במחשב, אתחלו את git, וחברו את מיקום GitHub כיעד מרוחק:

# create new directory
mkdir new-project
# enter new directory
cd new-project
# initialize git
git init
# attach remote
git remote add origin [email protected]:<username>/<repo>.git
# change default branch name
git branch -M main

עכשיו אפשר להתחיל לעבוד בספריית new-project שיצרתם.

#סימון

הטופס בדוגמה הזו פשוט למדי. הוא כולל מערך של סוגי קלט שונים, כולל תיבות סימון לבחירת כמה ערכים. הטופס גם לא כולל אימותים, כדי שתוכלו לראות איך ערכים ריקים ו/או חסרים מתפרשים בשרת.

בפרויקט הדוגמה הזה תשתמשו רק ב-HTML רגיל. אפשר להשתמש במסגרת JavaScript המועדפת עליכם, אבל נבחרו שפות גולמיות לשם פשטות והיכרות: כל המסגרות מפשטות ו/או מייצרות תוצאה דומה.

צרו public/index.html בספריית הפרויקט. כל נכסי צד הלקוח יהיו בתוך ספריית public הזו, וקובץ index.html הזה ישמש כדף הבית של האתר.

העתיקו והדביקו את התוכן הבא לקובץ public/index.html:

<html lang="en">
	<head>
		<meta charset="utf8" />
		<title>Form Demo</title>
		<meta name="viewport" content="width=device-width,initial-scale=1" />
	</head>
	<body>
		<form method="POST" action="/api/submit">
			<div class="input">
				<label for="name">Full Name</label>
				<input id="name" name="name" type="text" />
			</div>

			<div class="input">
				<label for="email">Email Address</label>
				<input id="email" name="email" type="email" />
			</div>

			<div class="input">
				<label for="referers">How did you hear about us?</label>
				<select id="referers" name="referers">
					<option hidden disabled selected value></option>
					<option value="Facebook">Facebook</option>
					<option value="Twitter">Twitter</option>
					<option value="Google">Google</option>
					<option value="Bing">Bing</option>
					<option value="Friends">Friends</option>
				</select>
			</div>

			<div class="checklist">
				<label>What are your favorite movies?</label>
				<ul>
					<li>
						<input id="m1" type="checkbox" name="movies" value="Space Jam" />
						<label for="m1">Space Jam</label>
					</li>
					<li>
						<input
							id="m2"
							type="checkbox"
							name="movies"
							value="Little Rascals"
						/>
						<label for="m2">Little Rascals</label>
					</li>
					<li>
						<input id="m3" type="checkbox" name="movies" value="Frozen" />
						<label for="m3">Frozen</label>
					</li>
					<li>
						<input id="m4" type="checkbox" name="movies" value="Home Alone" />
						<label for="m4">Home Alone</label>
					</li>
				</ul>
			</div>

			<button type="submit">Submit</button>
		</form>
	</body>
</html>

מסמך ה-HTML הזה יכיל טופס עם כמה שדות שהמשתמש ימלא. מכיוון שאין כללי אימות בתוך הטופס, כל השדות אופציונליים והמשתמש יכול לשלוח טופס ריק. בדוגמה הזו, זו התנהגות מכוונת.

תוכן אופציונלי

מבחינה טכנית, רק ה-<form> ורכיבי הבן שלו נחוצים. ה-<head> ותגיות <html> ו-<body> העוטפות הן אופציונליות ולא הכרחיות במסמך HTML תקין.

בשלב הזה דף ה-HTML גם לגמרי בלי עיצוב, והוא נשען על ממשק המשתמש ועל לוחות הצבעים שמוגדרים כברירת מחדל בדפדפנים. עיצוב הדף הוא אופציונלי לחלוטין ולא נחוץ כדי שהטופס יפעל. אם רוצים לצרף גיליון סגנונות CSS, אפשר להוסיף רכיב <link>. פנו לקוד המקור של המדריך המוגמר לדוגמה או להשראה: הדרישה היחידה היא שגם גיליון הסגנונות CSS יימצא בתוך ספריית public.

#Worker

טופס ה-HTML הושלם ומוכן לפריסה. כשהמשתמש שולח את הטופס הזה, כל הנתונים יישלחו בבקשת POST לכתובת ה-URL /api/submit. זה נובע ממאפייני method ו-action של הטופס. עם זאת, כרגע אין מטפל בקשות בכתובת /api/submit. עכשיו תיצרו אותו.

Cloudflare Pages מציע את התכונה Functions, שמאפשרת להגדיר ולפרוס Workers להתנהגויות דינמיות.

Functions מקושרים לספריית functions ובונים בנוחות מטפלי בקשות URL ביחס למבנה הקבצים של functions. לדוגמה, הקובץ functions/about.js ימופה לכתובת ה-URL /about, ו-functions/hello/[name].js יטפל בתבנית ה-URL /hello/:name, כאשר :name הוא כל מקטע URL תואם. למידע נוסף, פנו לתיעוד Functions routing.

כדי להגדיר מטפל עבור /api/submit, צריך ליצור קובץ functions/api/submit.js. המשמעות היא שספריות functions ו-public צריכות להיות אחיות, עם מבנה פרויקט כולל דומה לזה:

├── functions
│   └── api
│       └── submit.js
└── public
    └── index.html

ה-<form> ישלח בקשות POST, ולכן הקובץ functions/api/submit.js צריך לייצא מטפל onRequestPost:

/**
 * POST /api/submit
 */
export async function onRequestPost(context) {
	// TODO: Handle the form submission
}

הפרמטר context הוא אובייקט שמלא בכמה ערכים שעשויים לעניין. בדוגמה הזו צריך רק את אובייקט ה-Request, שאפשר לגשת אליו דרך המפתח context.request.

כאמור, <form> משתמש כברירת מחדל בסוג ה-MIME application/x-www-form-urlencoded בעת השליחה. ובתרחישים מתקדמים יותר, נדרש המאפיין enctype="multipart/form-data". למרבה המזל, את שני סוגי ה-MIME אפשר לנתח ולהתייחס אליהם כ-FormData. המשמעות היא שעם Workers, שכוללים את Pages Functions, אפשר להשתמש במנתח המובנה Request.formData.

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

/**
 * POST /api/submit
 */
export async function onRequestPost(context) {
	try {
		let input = await context.request.formData();
		let pretty = JSON.stringify([...input], null, 2);
		return new Response(pretty, {
			headers: {
				"Content-Type": "application/json;charset=utf-8",
			},
		});
	} catch (err) {
		return new Response("Error parsing JSON content", { status: 400 });
	}
}

עם המטפל הזה במקום, הדוגמה עכשיו מתפקדת במלואה. כשמתקבלת שליחה, ה-Worker ישיב עם רשימת JSON של זוגות המפתח והערך של FormData.

עם זאת, אם רוצים להשיב עם אובייקט JSON במקום זוגות המפתח והערך (מערך של מערכים), צריך לעשות זאת ידנית. לאחרונה, JavaScript הוסיף את כלי העזר Object.fromEntries. זה עובד היטב בחלק מהמקרים. עם זאת, ה-<form> בדוגמה כולל רשימת סימון movies שמאפשרת כמה ערכים. אם משתמשים ב-Object.fromEntries, האובייקט שנוצר ישמור רק אחד מערכי movies, ויזרוק את השאר. כדי להימנע מכך, צריך לכתוב כלי עזר משלכם מ-FormData ל-Object:

/**
 * POST /api/submit
 */
export async function onRequestPost(context) {
	try {
		let input = await context.request.formData();

		// Convert FormData to JSON
		// NOTE: Allows multiple values per key
		let output = {};
		for (let [key, value] of input) {
			let tmp = output[key];
			if (tmp === undefined) {
				output[key] = value;
			} else {
				output[key] = [].concat(tmp, value);
			}
		}

		let pretty = JSON.stringify(output, null, 2);
		return new Response(pretty, {
			headers: {
				"Content-Type": "application/json;charset=utf-8",
			},
		});
	} catch (err) {
		return new Response("Error parsing JSON content", { status: 400 });
	}
}

הקטע הסופי (למעלה) מאפשר ל-Worker לשמור את כל הערכים, ולהחזיר תגובת JSON עם ייצוג מדויק של שליחת ה-<form>.

#פריסה

עכשיו אתם מוכנים לפרוס את הפרויקט.

אם עדיין לא עשיתם זאת, שמרו את ההתקדמות בתוך git ואז דחפו את ה-commit או ה-commits למאגר GitHub:

# Add all files
git add -A
# Commit w/ message
git commit -m "working example"
# Push commit(s) to remote
git push -u origin main

העבודה נמצאת עכשיו בתוך מאגר GitHub, ולכן גם Pages יכול לגשת אליה.

אם זה פרויקט Cloudflare Pages הראשון שלכם, פנו למדריך Get started להדרכה מלאה. אחרי בחירת מאגר GitHub המתאים, צריך להגדיר את הפרויקט עם הגדרות הבנייה הבאות:

  • Project name: לפי בחירתכם
  • Production branch: main
  • Framework preset: None
  • Build command: None / Empty
  • Build output directory: public

אחרי לחיצה על הכפתור Save and Deploy, פרויקט Pages יתחיל את הפריסה הראשונה שלו. כשהיא מצליחה, תוצג לכם תת-דומיין ייחודי *.pages.dev וקישור להדגמה החיה.

במדריך זה בניתם ופרסתם אתר ואת לוגיקת צד השרת שלו באמצעות Cloudflare Pages עם שילוב ה-Workers שלו. יצרתם מסמך HTML סטטי עם טופס שמתקשר עם מטפל Worker כדי לנתח את בקשות השליחה.

אם תרצו לעיין בקוד המקור המלא של האפליקציה הזו, אפשר למצוא אותו ב-GitHub.

#משאבים קשורים