express-10 表單處理


從用戶那里收集信息的常用方法就是使用HTML表單。無論是使用瀏覽器提交表單,還是使用AJAX提交,或是運用精巧的前端控件,底層機制通常仍舊是HTML表單。

向服務器發送客戶端數據###

向服務器發送客戶端數據有兩種方式:查詢字符串和請求正文。通常,如果是使用查詢字符串,就發起了一個GET請求;如果是使用請求正文,就發起了一個POST請求。

有一種普遍的誤解是POST請求是安全的,而GET請求不安全。事實上如果使用HTTPS協議,兩者都是安全的;如果不使用,則都不安全。如果不使用HTTPS協議,入侵者會像查看GET請求的查詢字符串一樣,輕松查看POST請求的報文數據。然而,如果你使用GET請求,用戶會在查詢字符串中看到所有的輸入數據(包括隱藏域)。此外,瀏覽器會限制查詢字符串的長度(對請求正文沒有長度限制)。基於這些原因,一般推薦使用POST進行表單提交。

HTML表單###

例子:

<form action="/process" method="POST">
   <input type="hidden" name="hush" val="hidden, but not secret!">
   <div>
      <label for="fieldColor">Your favorite color: </label>
      <input type="text" id="fieldColor" name="color">
   </div>
   <div>
      <button type="submit">Submit</button>
   </div>
</form>

請注意,在<form>標記中提交方法被明確地指定為POST:如果不這么做,默認進行GET提交。action的值被指定為用於接收表單數據的URL。如果你忽略這個值,表單會提交到它被加載進來時的同一URL。我建議你始終都為action提供一個有效值,即使是使用AJAX提交(這會防止你丟失數據)

從服務器的角度來看,最重要的屬性是<input>域中的name屬性,這樣服務器才能識別字段。name屬性與id屬性是截然不同的,后者只適用於樣式和前端功能(它不會發送到服務器端)。

HTML並不會限制在同一個頁面上有多個表單(遺憾的是有些早期服務器框架有限制,比如ASP)。建議保持表達邏輯上的一致性:一個表單應該只包含想要提交的字段。如果一個頁面上有兩個不同的action,請使用兩個不同的表單。例如,在一個頁面上一個表單用於網站搜索,另一個表單用於登錄獲得電子簡訊。只用一個大表單是可行的,可以根據用戶點擊的按鈕判斷采用哪個action,但是這會讓人頭疼,而且通常對於殘疾人是不友好的(由於無障礙瀏覽器呈現表單的方式)。

當用戶提交表單時,/process URL被請求,字段值在請求正文中被傳輸到服務器。

編碼###

當表單被提交(通過瀏覽器或AJAX)時,某種程度上它必須被編碼。如果不明確地指定編碼,則默認為application/x-wwwform-urlencoded(這只是一個冗長的用於“URL編碼”的媒體類型)。它是受Express支持的基本、易用的編碼。

如果需要上傳文件,事情就開始變得復雜起來。使用URL編碼很難發送文件,所以不得不使用multipart/form-data編碼類型,這並不直接由Express處理(事實上,Express仍然支持這種編碼,但是在Express的下一個版本它會被移除,並且它也並不被建議使用)。

處理表單的不同方式###

如果不使用AJAX,唯一的選擇是用瀏覽器提交表單,這會重新加載頁面。然而,如何重新加載頁面由你來決定。處理表單時有兩件事需要考慮:處理表單是哪個路徑(action),以及向瀏覽器發出怎樣的響應。

如果表單使用的是method="POST"(推薦使用),那么展現表單和處理表單通常使用相同的路徑:這樣可以區分開來,因為前者是一個GET請求,而后者是一個POST請求。如果采用這種方法,就可以省略表單上的action屬性。

無論使用什么路徑來處理表單,必須決定如何響應瀏覽器。

  • 直接響應HTML

處理表單之后,可以直接向瀏覽器返回HTML(例如,一個視圖)。如果用戶嘗試重新加載頁面,這種方法就會產生警告,並且會影響書簽和后退按鈕。基於這些原因,不推薦這種方法。

  • 302重定向:

雖然這是一種常見的方法,但這是對響應代碼302本義的濫用。HTTP 1.1增加了響應代碼303,一種更合適的代碼。除非你有理由讓瀏覽器回到1996年,否則你應該改用303。

  • 303重定向:

HTTP 1.1添加了響應代碼303用來解決302重定向的濫用。HTTP規范明確地表明瀏覽器303重定向后,無論之前是什么方法,都應該使用GET請求。這是用於響應表單提交請求的推薦方法。

由於推薦通過303重定向來響應表單提交,接下來的問題是:“重定向指向哪里?”。下面是一些常用的方法。

  • 重定向到專用的成功/失敗頁面

這種方法需要為適當的成功或失敗消息提供URL。例如,如果一個用戶通過促銷郵件注冊,但是有一個數據庫錯誤,可能希望重定向到/error/database。如果用戶的電子郵件地址是無效的,可以重定向到/error/invalid-email。如果一切順利,可以重定向到/promo-email/thank-you。這種方法的一個優點是便於分析:訪問/promo-email/thank-you頁面的人數應該和登錄促銷郵件的人數大致相關。而且這種方法也很容易實現。然而它還有一些缺點。這意味着你\必須針對每一種可能性來分配URL,這也意味着頁面設計、編寫復制和維護。另一個缺點是用戶體驗欠佳

  • 運用flash消息重定向到原位置

由於有許多小表單分散在整個站點中(例如,電子郵件登錄),最好的用戶體驗是不干擾用戶的導航流。也就是說,需要一個不用離開當前頁面就能提交表單的方法。當然,要做到這一點,可以用AJAX,但是如果你不想用AJAX(或者你希望備用機制能夠提供一個好的用戶體驗),可以重定向回用戶之前瀏覽的頁面。最簡單的方法是在表單中使用一個隱藏域來存放當前URL。因為你想有一種反饋,表明用戶的提交信息已收到,所以你可以使用flash消息。

  • 運用flash消息重定向到新位置

大型表單通常都會有自己的頁面,一旦提交就沒有必要停留在這個頁面上了。在這種情況下,就要考慮一下用戶接下來想去哪兒,並相應地進行重定向。

如果使用AJAX,推薦使用專門的URL。

Express表單處理###

如果使用GET進行表單處理,表單域在req.query對象中。如果使用POST(推薦使用的),需要引入中間件來解析URL編碼體。

  • 首先,安裝body-parser中間件(npm install --save body-parser),然后引入:
var bodyParser = require('body-parser');
app.use(bodyParser());

有時,你會發現有些地方不鼓勵使用express.bodyParser,並且理由充分。然而,這個問題在Epress 4.0中消失了,body-parser中間件是安全的並且推薦使用。

  • 創建/views/newsletter.handlebars
<h2>Sign up for our newsletter to receive news and specials!</h2>
<form class="form-horizontal" role="form"
action="/process?form=newsletter" method="POST">
    <input type="hidden" name="_csrf" value="{{csrf}}">
    <div class="form-group">
         <label for="fieldName" class="col-sm-2 control-label">Name</label>
         <div class="col-sm-4">
             <input type="text" class="form-control"
              id="fieldName" name="name">
         </div>
    </div>
    <div class="form-group">
         <label for="fieldEmail" class="col-sm-2 control-label">Email</label>
         <div class="col-sm-4">
              <input type="email" class="form-control" required
              id="fieldName" name="email">
         </div>
    </div>
    <div class="form-group">
         <div class="col-sm-offset-2 col-sm-4">
              <button type="submit" class="btn btn-default">Register</button>
         </div>
    </div>
</form>
  • 應用文件
app.get('/newsletter', function(req, res){
    //我們會在后面學到CSRF……目前, 只提供一個虛擬值
    res.render('newsletter', { csrf: 'CSRF token goes here' });
});

app.post('/process', function(req, res){
    console.log('Form (from querystring): ' + req.query.form);
    console.log('CSRF token (from hidden form field): ' + req.body._csrf);
    console.log('Name (from visible form field): ' + req.body.name);
    console.log('Email (from visible form field): ' + req.body.email);
    res.redirect(303, '/thank-you');
});

在處理程序中,我們將重定向到“thank you”視圖。我們可以在此渲染視圖,但是如果這樣做,訪問者的瀏覽器地址欄仍舊是/process,這可能會令人困惑。發起一個重定向可以解決這個問題。

在這種情況下使用303(或302)重定向,而不是301重定向,這一點非常重要。301重定向是“永久”的,意味着瀏覽器會緩存重定向目標。如果使用301重定向並且試圖第二次提交表單,瀏覽器會繞過整個/process處理程序直接進入/thank you頁面,因為它正確地認為重定向是永久性的。另一方面,303重定向告訴瀏覽器“是的,你的請求有效,可以在這里找到響應”,並且不會緩存重定向目標。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM