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重定向告诉浏览器“是的,你的请求有效,可以在这里找到响应”,并且不会缓存重定向目标。

原文地址:https://www.cnblogs.com/jinkspeng/p/4281488.html