HTML表單是用戶和web站點或應用程序之間交互的主要內容之一。它們容許用戶將數據發送到web站點。大多數狀況下,數據被髮送到web服務器,可是web頁面也能夠攔截它本身並使用它。php
HTML表單是由一個或多個小部件組成的。這些小部件能夠是文本字段(單行或多行)、選擇框、按鈕、複選框或單選按鈕。大多數狀況下,這些小部件與描述其目的的標籤配對——正確實現的標籤可以清楚地指示視力正常的用戶和盲人用戶輸入表單輸入的內容。node
HTML表單和常規HTML文檔的主要區別在於,大多數狀況下,表單收集的數據被髮送到web服務器。在這種狀況下,您須要設置一個web服務器來接收和處理數據。mysql
<form action="/my-handling-form-page" method="post"> <div> <label for="name">Name:</label> <input type="text" id="name" /> </div> <div> <label for="mail">E-mail:</label> <input type="email" id="mail" /> </div> <div> <label for="msg">Message:</label> <textarea id="msg"></textarea> </div> </form>
<label>元素上使用for屬性;它是將標籤連接到表單小部件的一種正式方式。這個屬性引用相應的小部件的id。最明顯的一個好處是容許用戶單擊標籤以激活相應的小部件。(點擊標籤名,對應的輸入框自動獲取焦點)web
<div class="button"> <button type="submit">Send your message</button> </div>
<button>元素也接受一個 type屬性,它接受三個值中的一個:submit, reset或者 button。sql
form { /* 居中表單 */ margin: 0 auto; width: 400px; /* 顯示錶單的輪廓 */ padding: 1em; border: 1px solid #CCC; border-radius: 1em; } /* 選擇 <div> 元素以後緊跟的每一個 <div> 元素。 */ form div + div { margin-top: 1em; } label { /* 確保全部label大小相同並正確對齊 */ display: inline-block; width: 90px; text-align: right; } input, textarea { /* 確保全部文本輸入框字體相同 textarea默認是等寬字體 */ font: 1em sans-serif; /* 使全部文本輸入框大小相同 */ width: 300px; box-sizing: border-box; /* 調整文本輸入框的邊框樣式 */ border: 1px solid #999; } /* 選擇得到焦點的輸入字段(元素),並設置其樣式 */ input:focus, textarea:focus { /* 給激活的元素一點高亮效果 */ border-color: #000; } textarea { /* 使多行文本輸入框和它們的label正確對齊 */ vertical-align: top; /* 給文本留下足夠的空間 */ height: 5em; } .button { /* 把按鈕放到和文本輸入框同樣的位置 */ padding-left: 90px; /* 和label的大小同樣 */ } button { /* 這個外邊距的大小與label和文本輸入框之間的間距差很少 */ margin-left: .5em; }
display: inline-block; 元素可以在同一行顯示。
display:inline-block 的佈局方式和浮動的佈局方式。數據庫
<form action="/my-handling-form-page" method="post"> <div> <label for="name">Name:</label> <input type="text" id="name" name="user_name" /> </div> <div> <label for="mail">E-mail:</label> <input type="email" id="mail" name="user_email" /> </div> <div> <label for="msg">Message:</label> <textarea id="msg" name="user_message"></textarea> </div> ...
表單會發送三個已命名的數據塊 "user_name", "user_email", 和 "user_message"。這些數據將用使用HTTP POST 方法,把信息發送到URL爲 "/my-handling-form-page"目錄下。數組
<form> <fieldset> <legend>Fruit juice size</legend> <p> <input type="radio" name="size" id="size_1" value="small"> <label for="size_1">Small</label> </p> <p> <input type="radio" name="size" id="size_2" value="medium"> <label for="size_2">Medium</label> </p> <p> <input type="radio" name="size" id="size_3" value="large"> <label for="size_3">Large</label> </p> </fieldset> </form>
多個標籤瀏覽器
<div> <label for="username">Name: <abbr title="required">*</abbr></label> <input id="username" type="text" name="username"> </div>
通用屬性安全
單行文本域服務器
<input type="text" id="comment" name="comment" value="I'm a text field">
<select id="groups" name="groups"> <optgroup label="fruits"> <option>Banana</option> <option selected>Cherry</option> <option>Lemon</option> </optgroup> <optgroup label="vegetables"> <option>Carrot</option> <option>Eggplant</option> <option>Potato</option> </optgroup> </select>
2.多選選擇框
經過將multiple屬性添加到<select>元素,您能夠容許用戶經過操做系統提供的默認機制來選擇幾個值。
<select multiple id="multi" name="multi"> <option>Banana</option> <option>Cherry</option> <option>Lemon</option> </select>
3.自動補全輸入框 <datalist>
<label for="myFruit">What's your favorite fruit?</label> <input type="text" name="myFruit" id="myFruit" list="mySuggestion"> <datalist id="mySuggestion"> <option>Apple</option> <option>Banana</option> <option>Blackberry</option> <option>Blueberry</option> <option>Lemon</option> <option>Lychee</option> <option>Peach</option> <option>Pear</option> </datalist>
4.可選中項
// 複選 <input type="checkbox" checked id="carrots" name="carrots" value="carrots"> // 單選 <input type="radio" checked id="soup" name="meal">
<fieldset> <legend>What is your favorite meal?</legend> <ul> <li> <label for="soup">Soup</label> <input type="radio" checked id="soup" name="meal" value="soup"> </li> <li> <label for="curry">Curry</label> <input type="radio" id="curry" name="meal" value="curry"> </li> <li> <label for="pizza">Pizza</label> <input type="radio" id="pizza" name="meal" value="pizza"> </li> </ul> </fieldset>
1.數字
// 這將建立一個數字小部件,其值被限制爲1到10之間的任何值,而其增長和減小按鈕的值將更改成2。 <input type="number" name="age" id="age" min="1" max="10" step="2">
2.滑塊
// 滑塊的一個問題是,它們不提供任何形式的視覺反饋,以瞭解當前的值是什麼。您須要使用JavaScript來添加這一點 <label for="beans">How many beans can you eat?</label> // 這個例子建立了一個滑塊,它可能的值在0到500之間,而它的遞增/遞減按鈕改變值的值是+10和-10。 <input type="range" name="beans" id="beans" min="0" max="500" step="10"> <span class="beancount"></span> var beans = document.querySelector('#beans'); var count = document.querySelector('.beancount'); // 當前值 count.textContent = beans.value; // 改變時的函數 beans.oninput = function() { count.textContent = beans.value; }
https://developer.mozilla.org...
瀏覽器發送一個空的主體。由於主體是空的,若是使用該方法發送一個表單,那麼發送到服務器的數據將被追加到URL。
須要考慮到HTTP請求體中提供的數據:「嘿,服務器,看一下這些數據,而後給我回一個適當的結果。」若是使用該方法發送表單,則將數據追加到HTTP請求的主體中。
文件是二進制數據——或者被認爲是這樣的——而全部其餘數據都是文本數據。因爲HTTP是一種文本協議,因此處理二進制數據有特殊的要求。
enctype 屬性
該屬性容許您指定在提交表單時所生成的請求中的Content-Type的HTTP數據頭的值。這個數據頭很是重要,由於它告訴服務器正在發送什麼樣的數據。默認狀況下,它的值是application/x-www-form-urlencoded。它的意思是:「這是已編碼爲URL參數的表單數據。」
若是你想要發送文件,你須要額外的三個步驟:
<form method="post" enctype="multipart/form-data"> <div> <label for="file">Choose a file</label> <input type="file" id="file" name="myFile"> </div> <div> <button>Send the file</button> </div> </form>
每次向服務器發送數據時,都須要考慮安全性。到目前爲止,HTML表單是最多見的攻擊媒介(可能發生攻擊的地方)。這些問題歷來都不是來自HTML表單自己,它們來自於服務器如何處理數據。
根據你所作的事情,你會遇到一些很是有名的安全問題:
XSS 和 CSRF
跨站腳本(XSS)和跨站點請求僞造(CSRF)是常見的攻擊類型,它們發生在當您將用戶發送的數據顯示給用戶或另外一個用戶時。
XSS容許攻擊者將客戶端腳本注入到其餘用戶查看的Web頁面中。攻擊者可使用跨站點腳本攻擊的漏洞來繞過諸如同源策略之類的訪問控制。這些攻擊的影響可能從一個小麻煩到一個重大的安全風險。
CSRF攻擊相似於XSS攻擊,由於它們以相同的方式攻擊——向Web頁面中注入客戶端腳本——但它們的目標是不一樣的。CSRF攻擊者試圖將特權升級到特權用戶(好比站點管理員)的權限,以執行他們不該該執行的操做(例如,將數據發送給一個不受信任的用戶)。
XSS攻擊利用用戶對web站點的信任,而CSRF攻擊則利用網站爲其用戶提供的信任。
爲了防止這些攻擊,您應該始終檢查用戶發送給服務器的數據(若是須要顯示),儘可能不要顯示用戶提供的HTML內容。相反,您應該處理用戶提供的數據,這樣您就不會逐字地顯示它。當今市場上幾乎全部的框架都實現了一個最小的過濾器,它能夠從任何用戶發送的數據中刪除HTML<script>、<iframe> 和<object> 元素。這有助於下降風險,但並不必定會消除風險。
SQL注入
SQL 注入是一種試圖在目標web站點使用的數據庫上執行操做的攻擊類型。這一般包括髮送一個SQL請求,但願服務器可以執行它(一般,當應用服務器試圖存儲由用戶發送的數據時)。這其實是攻擊網站的主要途徑之一。
其後果多是可怕的,從數據丟失到經過使用特權升級控制整個網站基礎設施的攻擊。這是一個很是嚴重的威脅,您永遠不該該存儲用戶發送的數據,而不執行一些清理工做(例如,在php/mysql基礎設施上使用mysql_real_escape_string()。
HTTP數據頭注入和電子郵件注入
當您的應用程序基於表單上用戶的數據輸入構建HTTP頭部或電子郵件時,就會出現這種類型的攻擊。這些不會直接損害您的服務器或影響您的用戶,可是它們是一個更深刻的問題,例如會話劫持或網絡釣魚攻擊。
這些攻擊大可能是無聲的,而且能夠將您的服務器變成殭屍。
偏執:永遠不要相信你的用戶
那麼,你如何應對這些威脅呢?這是一個遠遠超出本指南的主題,可是有一些規則須要牢記。最重要的原則是:永遠不要相信你的用戶,包括你本身;即便是一個值得信賴的用戶也可能被劫持。
全部到達服務器的數據都必須通過檢查和消毒。
https://developer.mozilla.org...
https://developer.mozilla.org...
一共有三種方式來發送表單數據:包括兩種傳統的方法和一種利用formData對象的新方法.
異步發送表單數據的最古老方法是用DOM API構建表單,而後將其數據發送到隱藏的<iframe>。 要訪問提交的結果,請獲取<iframe>的內容。
<button onclick="sendData({test:'ok'})">點擊我!</button> // 首先建立一個用來發送數據的iframe. var iframe = document.createElement("iframe"); iframe.name = "myTarget"; // 必須把這個iframe插入當前文檔. window.addEventListener("load", function () { iframe.style.display = "none"; document.body.appendChild(iframe); }); // 下面這個函數是真正用來發送數據的. // 它只有一個參數,一個包含鍵值對數據格式的對象. function sendData(data) { var name, form = document.createElement("form"), node = document.createElement("input"); // 註冊iframe的load事件處理程序,若是你須要在響應返回時執行一些操做的話. iframe.addEventListener("load", function () { alert("Yeah! Data sent."); }); form.action = "http://www.cs.tut.fi/cgi-bin/run/~jkorpela/echo.cgi"; form.target = iframe.name; for(name in data) { node.name = name; node.value = data[name].toString(); form.appendChild(node.cloneNode()); } // 表單元素須要添加到主文檔中. form.style.display = "none"; document.body.appendChild(form); form.submit(); // 表單提交後,就能夠刪除這個表單,不影響下次的數據發送. document.body.removeChild(form); }
XMLHttpRequest是進行HTTP請求的最安全和最可靠的方式。 要使用XMLHttpRequest發送表單數據,請經過對URL進行編碼來準備數據,並遵照表單數據請求的具體內容。
<button type="button" onclick="sendData({test:'ok'})">點擊我!</button> function sendData(data) { var XHR = new XMLHttpRequest(); var urlEncodedData = ""; var urlEncodedDataPairs = []; var name; // 將數據對象轉換爲URL編碼的鍵/值對數組。 for(name in data) { urlEncodedDataPairs.push(encodeURIComponent(name) + '=' + encodeURIComponent(data[name])); } // 將配對合併爲單個字符串,並將全部%-編碼空間替換爲 // 「+」字符;匹配瀏覽器窗體提交的行爲。 urlEncodedData = urlEncodedDataPairs.join('&').replace(/%20/g, '+'); // 定義成功數據提交時發生的狀況 XHR.addEventListener('load', function(event) { alert('Yeah! Data sent and response loaded.'); }); // 定義錯誤提示 XHR.addEventListener('error', function(event) { alert('哎呀!出了問題。'); }); // 創建咱們的請求 XHR.open('POST', 'https://example.com/cors.php'); // 爲表單數據POST請求添加所需的HTTP頭 XHR.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); // 最後,發送咱們的數據。 XHR.send(urlEncodedData); }
可使用 FormData 對象來構建用於傳輸的表單數據,或者獲取表單元素中的數據來管理它的發送方式。 請注意,FormData 對象是「只寫」,這意味着您能夠更改它們,但不檢索其內容。
<button type="button" onclick="sendData({test:'ok'})">點擊我!</button> function sendData(data) { var XHR = new XMLHttpRequest(); var FD = new FormData(); // 把咱們的數據添加到這個FormData對象中 for(name in data) { FD.append(name, data[name]); } // 定義數據成功發送並返回後執行的操做 XHR.addEventListener('load', function(event) { alert('Yeah! Data sent and response loaded.'); }); // 定義發生錯誤時執行的操做 XHR.addEventListener('error', function(event) { alert('Oups! Something goes wrong.'); }); // 設置請求地址和方法 XHR.open('POST', 'http://ucommbieber.unl.edu/CORS/cors.php'); // 發送這個formData對象,HTTP請求頭會自動設置 XHR.send(FD); }
你也能夠綁定一個 FormData 對象到一個 <form> 元素上。這會建立一個 FormData ,表明表單中包含的元素。
<form id="myForm"> <label for="myName">告訴我你的名字:</label> <input id="myName" name="name" value="John"> <input type="submit" value="提交"> </form>
window.addEventListener("load", function () { function sendData() { var XHR = new XMLHttpRequest(); // 咱們把這個 FormData 和表單元素綁定在一塊兒。 var FD = new FormData(form); // 咱們定義了數據成功發送時會發生的事。 XHR.addEventListener("load", function(event) { alert(event.target.responseText); }); // 咱們定義了失敗的情形下會發生的事 XHR.addEventListener("error", function(event) { alert('哎呀!出了問題。'); }); // 咱們設置了咱們的請求 XHR.open("POST", "http://ucommbieber.unl.edu/CORS/cors.php"); // 發送的數據是由用戶在表單中提供的 XHR.send(FD); } // 咱們須要獲取表單元素 var form = document.getElementById("myForm"); // 接管表單的提交事件 form.addEventListener("submit", function (event) { event.preventDefault(); sendData(); }); });
使用formData發送二進制數據很是簡單,只須要調用append方法將你須要發送的File對象或者Blob對象添加進去.
<form id="myForm"> <p> <label for="i1">文本數據:</label> <input id="i1" name="myText" value="一些文本數據"> </p> <p> <label for="i2">文件數據:</label> <input id="i2" name="myFile" type="file"> </p> <button>提交</button> </form>
// 由於咱們想獲取DOM節點, // 咱們在頁面加載時初始化咱們的腳本. window.addEventListener('load', function () { // 這些變量用於存儲表單數據 var text = document.getElementById("i1"); var file = { dom : document.getElementById("i2"), binary : null }; // 使用 FileReader API 獲取文件內容 var reader = new FileReader(); // 由於 FileReader 是異步的, 會在完成讀取文件時存儲結果 reader.addEventListener("load", function () { file.binary = reader.result; }); // 頁面加載時, 若是一個文件已經被選擇, 那麼讀取該文件. if(file.dom.files[0]) { reader.readAsBinaryString(file.dom.files[0]); } // 若是沒有,一旦用戶選擇了它,就讀取文件。 file.dom.addEventListener("change", function () { if(reader.readyState === FileReader.LOADING) { reader.abort(); } reader.readAsBinaryString(file.dom.files[0]); }); // 在咱們的主函數中發送數據 function sendData() { // 若是存在被選擇的文件,等待它讀取完成 // 若是沒有, 延遲函數的執行 if(!file.binary && file.dom.files.length > 0) { setTimeout(sendData, 10); return; } // 要構建咱們的多部分表單數據請求, // 咱們須要一個XMLHttpRequest 實例 var XHR = new XMLHttpRequest(); // 咱們須要一個分隔符來定義請求的每一部分。 var boundary = "blob"; // 將咱們的請求主體存儲於一個字符串中 var data = ""; // 因此,若是用戶已經選擇了一個文件 if (file.dom.files[0]) { // 在請求體中開始新的一部分 data += "--" + boundary + "\r\n"; // 把它描述成表單數據 data += 'content-disposition: form-data; ' // 定義表單數據的名稱 + 'name="' + file.dom.name + '"; ' // 提供文件的真實名字 + 'filename="' + file.dom.files[0].name + '"\r\n'; // 和文件的MIME類型 data += 'Content-Type: ' + file.dom.files[0].type + '\r\n'; // 元數據和數據之間有一條空行。 data += '\r\n'; // 添加二進制數據到請求體中 data += file.binary + '\r\n'; } // 文本數據是簡單的 // 開始一個新的部分在請求體中 data += "--" + boundary + "\r\n"; // 說它是表單數據,並命名它 data += 'content-disposition: form-data; name="' + text.name + '"\r\n'; // 元數據和數據之間有一條空行。 data += '\r\n'; // 添加文本數據到請求體中 data += text.value + "\r\n"; // 一旦完成,關閉請求體 data += "--" + boundary + "--"; // 定義成功提交數據執行的語句 XHR.addEventListener('load', function(event) { alert('✌!數據已發送且響應已加載。'); }); // 定義發生錯誤時作的事 XHR.addEventListener('error', function(event) { alert('哎呀!出了問題。'); }); // 創建請求 XHR.open('POST', 'https://example.com/cors.php'); // 添加須要的HTTP報頭來處理多部分表單數據POST請求 XHR.setRequestHeader('Content-Type','multipart/form-data; boundary=' + boundary); // 最後,發送數據。 XHR.send(data); } // 訪問表單… var form = document.getElementById("myForm"); // ……接管提交事件 form.addEventListener('submit', function (event) { event.preventDefault(); sendData(); }); });
https://developer.mozilla.org...
https://developer.mozilla.org...