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重定向告诉浏览器“是的,你的请求有效,可以在这里找到响应”,并且不会缓存重定向目标。
express-10 表单处理的更多相关文章
- ddms(基于 Express 的表单管理系统)源码学习
ddms是基于express的一个表单管理系统,今天抽时间看了下它的代码,其实算不上源码学习,只是对它其中一些小的开发技巧做一些记录,希望以后在项目开发中能够实践下. 数据层封装 模块只对外暴露mod ...
- Express ~ 获取表单 get 和 post 提交方式传送参数的对比
一,获取 get 提交的参数 var id = req.query.id || '' 二,获取 post 提交的参数 var name = req.body.name || ''
- from表单实现无跳转上传文件,接收页面后台数据。
本文基于我刚写的http://www.cnblogs.com/iwang5566/p/6287529.html进行了简单的扩展,实现页面无跳转表单数据提交,并接收后台返回的数据. 下载好,上一篇文章d ...
- HTML中的表单
1.HTML中表单元素的基本概念 HTML表单是HTML元素中较为复杂的部分,表单往往和脚本,动态页面,数据处理等功能相结合,因此是制作动态网站很重要的内容. 表单一般用来收集用户的输入信息 2.表单 ...
- validate表单校验插件笔记
1validation知识点 1 validation基础 validation插件下载http://bassistance.de/jquery-plugins/jquery-plugin-valid ...
- bootstrap基础学习【表单含按钮】(二)
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- php开发面试题---2、php常用面试题二(表单提交方式中的get和post有什么区别)
php开发面试题---2.php常用面试题二(表单提交方式中的get和post有什么区别) 一.总结 一句话总结: 数据位置:get参数在url里面,post在主体里面 数据大小:get几kb,pos ...
- express-11 表单处理(2)
处理AJAX表单 用Express处理AJAX表单非常简单:甚至可以使用相同的处理程序来处理AJAX请求和常规的浏览器回退. HTML文件 (/views/newsletter.handlebars) ...
- 10款精美的HTML5表单登录联系和搜索表单
1.HTML5/CSS3仿Facebook登录表单 这款纯CSS3发光登录表单更是绚丽多彩.今天我们要分享一款仿Facebook的登录表单,无论从外观还是功能上说,这款登录表单还是挺接近Faceboo ...
随机推荐
- 最牛逼android上的图表库MpChart(三) 条形图
最牛逼android上的图表库MpChart三 条形图 BarChart条形图介绍 BarChart条形图实例 BarChart效果 最牛逼android上的图表库MpChart(三) 条形图 最近工 ...
- 【leetcode】Insertion Sort List (middle)
Sort a linked list using insertion sort. 思路: 用插入排序对链表排序.插入排序是指每次在一个排好序的链表中插入一个新的值. 注意:把排好序的部分和未排序的部分 ...
- 【python】为什么修改全局的dict变量不用global关键字
转自:http://my.oschina.net/leejun2005/blog/145911?fromerr=qnPCgI19#OSC_h4_8 为什么修改字典d的值不用global关键字先声明呢? ...
- 字符串与byte数组转换
string weclome=""; byte[] data = new byte[1024]; //字符串转byte数组 data = Encoding.ASCII.GetByt ...
- [Android] 如何查看apk需要支持的Android版本
reference to : http://blog.csdn.net/huiguixian/article/details/39928089 如果有一个apk,需要知道他最低安装支持的Android ...
- Genesis不能运行Perl编译后的脚本
我们经常会遇到Genesis2000中C-shell的脚本不能正常运行的问题,而同样的程序在其它电脑上又可以正常运行,如果你能看看Genesis后台窗口,也就是后面那个黑乎乎的窗口(所谓的小DOS窗口 ...
- JS判断是否为IE浏览器 包含了IE11
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD ...
- 关于HTML5在动画制作工具Animatron的一些问题
Animatron是国外一款在线HTML5动画制作工具,网址:www.animatron.com 当然,想使用的话,是需要FQ的. 用animatron制作好的动画是可以下载为代码和GIF的,这时候付 ...
- android中点击空白处隐藏软键盘
InputMethodManager manager manager = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERV ...
- 命名空间 - PHP笔记
转: 概述 命名空间是一种封装事物的方法.在很多地方都可以见到这种抽象概念,比如在操作系统中,目录用来将相关文件分组,对于目录中的文件来说,目录就扮演了命名空间的角色.这个原理应用到程序设计领域就是命 ...