如何发送HTML表单数据
多数时候,HTML表单的目的只是为了把数据发给服务器,之后服务器再处理这些数据并发送响应给用户。虽然看起来挺简单的,但我们还是得注意一些事情以确保传送的数据不会破坏服务器、或者给你的用户制造麻烦。
数据会到哪里去
关于客户端/服务器架构
整个web都是基于一种基本的客户端/服务器架构,该架构可以归纳如下:
一个客户端(通常是Web浏览器)使用HTTP协议发送一个请求给服务器(通常是web服务器程序,譬如Apache, Nginx, IIS, Tomcat等等),而服务器则以相同的协议响应这个请求。
在客户端,HTML表单只是提供一种比较方便且用户友好的方式,用来配置发送给服务器的HTTP请求。这样用户就可以自己提供能被HTTP请求传送的信息。
客户端:定义如何发送数据
<form>元素能够定义其数据如何被发送,它所有的特性都是为了在用户点击发送按钮时,让你配置要发送的请求。其中最重要的两个特性是action和method。
action特性
该特性定义了数据会被发往何处,它的值必须是个合法的URL。若该特性未指定,则数据会发送到包含该表单的页面所在的URL。
示例
在下面的例子中,数据会发送至http://foo.com:
- <form action="http://foo.com">
这里,数据会被发送到表单页所在的服务器,但到达的却是服务器上不同的URL:
- <form action="/somewhere_else">
如下,当不指定任何特性时,表单数据会给发送到包含该表单的的页面:
- <form>
许多老旧的页面会使用下面的符号来表明,数据得被发送到包含该表单的的页面;这在当时是必须的,因为直到HTML5之前,action特性都是必填的。但现在就不再需要了。
- <form action="#">
注意:可以指定一个使用HTTPS(安全的HTTP)协议的URL,此时数据会随请求的其他部分一起加密,即使表单本身位于一个通过HTTP访问的不安全页面。此外,若表单位于一个安全的页面,而你却给action特性指定了一个不安全的HTTP URL,则所有的浏览器会在每次用户要发送数据时给他们一个安全警告,因为此时这些数据将不被加密。
method特性
该特性定义了数据如何被发送。HTTP协议提供了几种方式来执行一个请求;HTML表单数据可以通过其中至少方式来发送:GET和POST。
要理解这两种方式的不同,我们得回过头来来看下HTTP是如何工作的。当你想取得Web上的某个资源时,浏览器会发送一个请求给指定的URL。一个HTTP请求含有两个部分:包含和浏览器功能有关的一系列全局字段的请求头,以及包含要给服务器处理的信息的请求体。
GET方法
浏览器使用GET方法来请求服务器发回指定的资源:“嘿服务器,我想获得这个资源”。这种情况下,浏览器只会发送一个空的请求体,而正因如此,若浏览器使用该方式,那么发给服务器的数据会给追加到URL后面。
示例
考虑如下表单:
- <form action="http://foo.com" method="get">
- <input name="say" value="Hi">
- <input name="to" value="Mom">
- <button>Send my greetings</button>
- </form>
使用GET方法时,HTTP请求看起来就这样:
- GET /?say=Hi&to=Mom HTTP/1.1
- Host: foo.com
POST方法
POST方法则稍有不同,浏览器发送这个方法给服务器,用以请求一个和HTTP请求体里数据有关的响应:“嘿服务器,看看这些数据然后给我发回一个适当的结果”。若表单使用该方法发送,则数据会给追加到HTTP请求体里。
示例
考虑如下表单(和上面那个一样):
- <form action="http://foo.com" method="post">
- <input name="say" value="Hi">
- <input name="to" value="Mom">
- <button>Send my greetings</button>
- </form>
使用POST方法时,HTTP请求看起来就这样:
- POST / HTTP/1.1
- Host: foo.com
- Content-Type: application/x-www-form-urlencoded
- Content-Length: 13
- say=Hi&to=Mom
Content-length头部字段指示了请求体的大小,而Content-Type字段则标识了发往服务器的资源类型。我们将在稍后讨论下这些请求头。
当然,HTTP请求是不会展示给用户看的(若你想看到它们,还得使用诸如火狐的Web Console或者chrome Developer Tools等工具),唯一展示给用户的,只有访问的URL。所以使用GET请求时,用户将会在他们的地址栏看到数据,而使用POST请求则看不到。这点至关重要,原因如下:
- 若你要发送密码(或者任何敏感数据),那千万别用GET方法,否则该数据会不安全地展示在地址栏上。
- 若你想要发送大量数据,最好用POST方法,因为一些浏览器会限制URL的大小。此外,许多服务器也会限制接收的URL长度。
服务器端:处理数据
不论你选择哪种HTTP方法,服务器只会接收到一个字符串并将其解析,再以键/值对列表的形式获取数据。而如何访问这个列表,取决于你基于何种开发平台、以及用了何种框架。你使用的技术也会决定如何处理重复的键名,通常某个键名最后接收到的值是优先被选取的。
示例:原生PHP
PHP提供了几个全局对象来处理数据。假设你使用POST方法,下面的示例会直接提取你的数据并展示给用户。当然,要如何处理数据取决于你,你可以展示它、将其存进数据库、用邮件发送它、或者其他任何方式。
- <?php
- // 全局变量$_POST让你能够访问用POST方法发送的数据
- // 要访问用GET方法发送的数据,可以使用$_GET
- $say = htmlspecialchars($_POST['say']);
- $to = htmlspecialchars($_POST['to']);
- echo $say, ' ', $to;
这个示例会用我们发送的数据生成一个页面。考虑我们前面用的表单示例数据,输出结果会是:
- Hi Mom
示例:原生Python
下面的示例使用Python来做相同的事---将给定的数据展示到web页面上。其中使用了CGI Python package 来处理表单数据。
- #!/usr/bin/env python
- import html
- import cgi
- import cgitb; cgitb.enable() # 用于处理错误
- print("Content-Type: text/html") # 请求头字段,标识后面的内容是HTML
- print() # 空行,表示请求头的结束
- form = cgi.FieldStorage()
- say = html.escape(form["say"].value);
- to = html.escape(form["to"].value);
- print(say, " ", to)
结果和之前用PHP处理是一样的:
- Hi Mom
其它语言和框架
还有许多其他的服务端技术可以用来处理表单,比如Perl, Java, .Net, Ruby等等,选择你最喜欢的一种就好。我们很少直接使用这些技术,因为这么做得需要很多技巧来填坑;通常我们会在众多好用的框架中选择一种,这样会让表单的处理更容易些,比如:
- Symfony for PHP
- Django for Python
- Ruby On Rails for Ruby
- Grails for Java
值得注意的是,就算用了这些框架,处理表单是不一定就会变得轻松。但至少这样用起来会更好些,还能节省你不少时间。
特殊案例:发送文件
文件是HTML表单中一个特殊的例子,其他数据都是文本数据,而文件则一般是、或者被认为是二进制数据。由于HTTP是个文本协议,所以对处理二进制数据得有特别的要求。
enctype特性
该特性能让你指定HTTP请求头中的Content-Type字段值,这个字段的重要性在于,它能告诉服务器要发送的数据类型。其默认值是application/x-www-form-urlencoded,对应的解释是:“这份表单数据已被编码为URL格式”。
而当你想发送文件时,得先做两件事:
- 将method特性设置为POST,因为使用表单时,文件内容是不能被放到URL参数里的
- 将enctype特性的值设为multipart/form-data,这样数据就会被分割为多个部分,每个文件都会追加上和他们一起发送的表单有关的文本。
示例:
- <form method="post" enctype="multipart/form-data">
- <input type="file" name="myFile">
- <button>Send the file</button>
- </form>
注意:某些浏览器支持<input>元素的multiple特性,以便让一个input元素能发送多个文件。至于服务器会如何处理这些文件,就得取决于它用来什么技术了。如前所述,使用框架能让你的活的轻松些~
警告:为防止滥用,许多服务器会对文件和HTTP请求设置大小限制。所以,最好在发送文件之前和服务器管理员核实一下这个限制。
安全相关
每次要发数据给服务器前,你都得考虑下安全问题。HTML表单是针对服务器的首要攻击载体之一,但该危害的来源并非HTML表单本身,而在于服务器如何处理数据。
常见的安全问题
著名的安全问题有很多,如何划分取决于你在做什么:
XSS和CSRF
跨站脚本攻击(XSS)和跨站请求伪造(CSRF)是最常见的攻击类型,它们会在你展示由用户发给用户的数据时发生。
XSS让攻击者能再其他用户访问的Web页面上注入客户端脚本。攻击者会利用跨站脚本的脆弱性来绕过访问控制策略,譬如同源策略。这种攻击可以取得从小麻烦到严重安全危机不等的危害效果。
CSRF很像XSS,因为它们都以相同的方式开始---注入客户端脚本到Web页面,但它们的攻击目标却不同。CSRF攻击者会试着升级权限以成为一个高权限的用户(比如网站管理员),然后执行本不能够执行的动作(如把数据发送给不受信任的用户)。
XSS攻击利用了用户对网站的信任,而CSRF攻击则利用了网站对其用户的信任。
要防止此类攻击,就得时常校验用户发送给服务器的数据;同时(如果需要展示)也尽量别展示用户提供的HTML内容,而应该处理用户提供的数据,以避免将其原封不动地显示出来。目前几乎所有市面上的的框架,至少都会实现一个过滤器,用以移除用户提交数据中<script>, <iframe>, <object>等标签,这样有助于减轻风险,但并不意味着会根除它。
SQL注入
SQL注入是一种对目标网站的数据库执行动作的攻击方式。通常攻击者会发送一段SQL请求,并希望服务器能执行它(多数发生在应用服务器想存储数据之时)。这实际上已成为针对web站点的主要攻击载体之一。
该攻击的危害是很严重的,小到数据丢失、大到被攻击者通过权限升级访问整个网站架构。这确实是非常重大的威胁,所以你不应该存储那些用户提交而没经过特殊处理(例如,在PHP/MySQL架构下经过mysql_real_escape_string()处理)的数据。
HTTP头部注入和邮件注入
这种攻击会在你的应用使用用户在表单上输入的数据来构造HTTP头、或者email时发生。该攻击虽然不会危害你的服务器或者影响你的用户,但却会给更深处的问题大开方便之门,比如会话劫持、钓鱼攻击。
所有这些攻击往往都是悄无声息地发生的,而且会把你的服务器弄成肉鸡)。
偏执些:永远别信任你的用户
所以,要如何对抗这些威胁呢?这一点已超出本指南的主题范围了,但有几条规则时需要我们牢记的。最重要的一条就是:永远别信任你的用户,包括你自己;即使是受信任的用户也会有被劫持可能。
所有的到达你服务器的数据都必须被校验并处理,而且要一直保持,不能有例外。
- 过滤潜在的危险字符。要关注的哪些特定字符,取决于使用数据的上下文、也取决于你使用的服务器平台,而所有的服务端语言都会提供相应的功能。
- 限制传入的数据量,只允许有必要的。
- 把上传的文件放沙盒里(将它们存储到放到一个不同的服务器上,并且要访问到它们只有通过一个不同的子域名、或一个完全不同的域名才行)。
若你能遵循这三条规则,就应该能避免绝大多数问题,但一个更好的办法是让一个有资格的第三方来做安全审查,别以为你能看透所有潜在的问题。
结论
如你所见,发送表单数据时很简单的,但保障一个应用的安全就需要很多技术了。前端开发者不是那种去定义一个数据安全模型的角色,虽然可能得执行[客户端数据校验](),但是服务器也不能信任这些校验,因为它并不能确切知道客户端上到底发生过什么。
如何发送HTML表单数据的更多相关文章
- 【ASP.NET Web API教程】5.3 发送HTML表单数据:文件上传与多部分MIME
原文:[ASP.NET Web API教程]5.3 发送HTML表单数据:文件上传与多部分MIME 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面 ...
- 【ASP.NET Web API教程】5.2 发送HTML表单数据:URL编码的表单数据
原文:[ASP.NET Web API教程]5.2 发送HTML表单数据:URL编码的表单数据 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内 ...
- (转)WebApi发送HTML表单数据:文件上传与多部分MIME
5.3 Sending HTML Form Data5.3 发送HTML表单数据(2) 本文引自:http://www.cnblogs.com/r01cn/archive/2012/12/20/282 ...
- WebApi发送HTML表单数据:文件上传与多部分MIME
5.3 Sending HTML Form Data5.3 发送HTML表单数据(2) 本文引自:http://www.cnblogs.com/r01cn/archive/2012/12/20/282 ...
- hyper发送表单数据
前言 某个美丽的下午,运维把服务器上的nginx升级了,http协议也变成了http2.0,我本地的requests再也连接不到服务器,然后就找到了额hyper 但是hyper的文档写的很简单,而且相 ...
- JavaScript实现ajax发送表单数据
知识点: 1.重置表单数据 2.获取表单数据(纯JavaScript) 3.设置表单数据(纯JavaScript) 4.ajax发送数据到客户端 (1)设置请求头,自己组合数据 (2)实例化表单对象, ...
- 使用jQuery实现跨域提交表单数据
我们在WEB开发中有时会遇到这种情况,比如要从A网站收集用户信息,提交给B网站处理,这个时候就会涉及到跨域提交数据的问题.本文将给您介绍如何使用jQuery来实现异步跨域提交表单数据. 在jQue ...
- flask 处理表单数据
处理表单数据 表单数据的处理涉及很多内容,从获取数据到保存数据大致有以下步骤: 1. 解析请求,获取表单数据 2. 对数据进行必要的转换,比如讲勾选框的值转换成python的布尔值 3. 验证数 ...
- Ajax在jQuery中的应用 (4)向jsp提交表单数据
ajax技术带给我们的是良好的用户体验,同时,使用jquery可以简化开发,提高工作效率. 下面就介绍一下大致的开发步骤. 工具/原料 本文中使用的是 jquery-1.3.2.min.js 方法/步 ...
随机推荐
- Linux下inotify监控文件夹状态,发生变化后触发rsync同步
1.安装工具--inotifywget http://cloud.github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar ...
- VisualStudio2013内置SQLServer入门(二)--增删改查
前一篇 http://www.cnblogs.com/qixi233/p/4766451.html 这篇是sqlserver的操作 界面比较走心哈哈哈,将就着看,主要就是下面增删改查四个btn 对于s ...
- SGU 135.Drawing Lines
水题,不说了. #include <iostream> using namespace std; int f[70000]={1}; int n; int main(){ cin>& ...
- NewRowNeeded和UserAddedRow事件以及RowsAdded的区别使用
NewRowNeeded事件当 VirtualMode 属性为 true 时,将在用户定位到 DataGridView 底部的新行时发生,适合给新行建立一些默认数据和按规则应该产生的数据,但此时不推荐 ...
- [jQuery编程挑战]005 使用最短的代码生成元素的闪烁效果
<!DOCTYPE html> <html lang="zh"> <head> <meta charset="utf-8&quo ...
- Delphi中停靠技术的实现
随着软件技术的不断进步,软件界面也越来越美观,操作也越来越方便.综观市面上比较专业的各种软件,我们会发现大部分都提供窗体停靠的功能,特别象工具软件,基本上都或多或少有停靠功能.自然,Delphi也支持 ...
- python【第二篇】列表、元组、字典及文件操作
本节内容 列表 元组操作 字符串操作 字典操作 集合操作 文件操作 字符编码与转码 1.列表 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作:列表有序.可变.元素 ...
- IOS--UIImageView的使用方法
IOS--UIImageView的使用方法 //初始化 UIImageView *imageView=[[UIImageView alloc] initWithFrame:CGRectMake(10 ...
- Ajax 的同步与异步
1.Ajax的工作原理如图: 2.同步 XMLHttpRequest 对象用于和服务器交换数据. XMLHttpRequest 对象如果要用于 AJAX 的话,其 open() 方法的 async 参 ...
- ha666_go运行环境配置
项目地址:http://git.oschina.net/ha666/ha666_go 服务器配置: CPU: 1核 内存: 1024 MB 操作系统: CentOS 7.0 64位 内网IP: 10. ...