浏览器原生 form 表单POST 数据的两种方式
我们在提交表单的时候,form表单参数中会有一个enctype的参数。enctype指定了HTTP请求的Content-Type。
常用有两种:application/x-www-form-urlencoded和multipart/form-data。
application/x-www-form-urlencoded: 窗体数据被编码为名称/值对,并且将提交的数据进行urlencode。默认情况下,我们所有的表单提交都是通过这种默认的方式实现的。
multipart/form-data: 窗体数据被编码为一条消息,页上的每个控件对应消息中的一个部分。
当action为get时候,浏览器用x-www-form-urlencoded的编码方式把form数据转换成一个字串(name1=value1&name2=value2...),然后把这个字串append到url后面,用?分割,加载这个新的url。
当action为post时候,浏览器把form数据封装到http body中,然后发送到server。 如果没有type=file的控件,用默认的application/x-www-form-urlencoded就可以了。
请求标头:
请求正文:
- loginType=1&loginName=operator&pwd=%E1%8D%B0%E1%8D%B0%E1%8D%B0%E1%8D%B0%E1%8D%B0%E1%8D%B0&verifyCode=6987
首先,Content-Type 被指定为 application/x-www-form-urlencoded;其次,提交的数据按照 key1=val1&key2=val2 的方式进行编码,key 和 val 都进行了 URL 转码。大部分服务端语言都对这种方式有很好的支持。
但是如果有type=file的话,就要用到multipart/form-data了。浏览器会把整个表单以控件为单位分割,并为每个部分加上Content-Disposition(form-data或者file),Content-Type(默认为text/plain),name(控件name)等信息,并加上分割符(boundary)。
Multipart/form-data其实就是浏览器用表单上传文件的方式。最常见的情境是:在写邮件时,向邮件后添加附件,附件通常使用表单添加,也就是用multipart/form-data格式上传到服务器。
具体的步骤是怎样的呢?
首先,客户端和服务器建立连接(TCP协议)。
第二,客户端可以向服务器端发送数据。因为上传文件实质上也是向服务器端发送请求。
第三,客户端按照符合“multipart/form-data”的格式向服务器端发送数据。
服务端接收的http请求标头:
请求正文:
- -----------------------------7e11a616672236
- Content-Disposition: form-data; name="id"
- 17e832d6a79744eaae6d79237e82e3a4
- -----------------------------7e11a616672236
- Content-Disposition: form-data; name="templateType"
- 1
- -----------------------------7e11a616672236
- Content-Disposition: form-data; name="file"; filename=""
- Content-Type: application/octet-stream
- <二进制文件数据未显示>
- ---------------------------7e11a616672236
- Content-Disposition: form-data; name="imagesTemplate"
- -----------------------------7e11a616672236
- Content-Disposition: form-data; name="attachTemplate"
- -----------------------------7e11a616672236
- Content-Disposition: form-data; name="ajax"
- 1
- -----------------------------7e11a616672236--
这行指出这个请求是“multipart/form-data”格式的,且“boundary”是 “---------------------------7e11a616672236”这个字符串。
不难想象,“boundary”是用来隔开表单中不同部分数据的。例子中的表单就有 6 部分数据,用“boundary”隔开。“boundary”一般由系统随机产生,但也可以简单的用“-------------”来代替。
实际上,每部分数据的开头都是由"--" + boundary开始,而不是由 boundary 开始。仔细看才能发现下面的开头这段字符串实际上要比 boundary 多了个 “--”
紧接着 boundary 的是该部分数据的描述。
在请求的最后,则是 "--" + boundary + "--" 表明表单的结束。
需要注意的是,在html协议中,用 “/r/n” 换行,而不是 “/n”。
附C#组装代码:
- var memStream = new MemoryStream();
- //https支持
- ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(CheckValidationResult);
- HttpWebRequest request = (HttpWebRequest)WebRequest.Create(httpUrl);
- // 边界符
- var boundary = "---------------" + DateTime.Now.Ticks.ToString("x");
- // 边界符
- var beginBoundary = Encoding.ASCII.GetBytes("--" + boundary + "\r\n");
- // 最后的结束符
- var endBoundary = Encoding.ASCII.GetBytes("--" + boundary + "--\r\n");
- memStream.Write(beginBoundary, , beginBoundary.Length);
- // 设置属性
- request.Method = "POST";
- request.Timeout = ;
- request.ReadWriteTimeout = ;
- request.ContentType = "multipart/form-data; boundary=" + boundary;
- var stringKeyHeader = "Content-Disposition: form-data; name=\"{0}\"" +
- "\r\n\r\n{1}\r\n";
- var header = string.Format(stringKeyHeader, "REQMESSAGE", bodyJson);
- var headerbytes = Encoding.UTF8.GetBytes(header);
- memStream.Write(headerbytes, , headerbytes.Length);
- memStream.Write(beginBoundary, , beginBoundary.Length);
- header = string.Format(stringKeyHeader, "AUTHMESSAGE", authJson);
- headerbytes = Encoding.UTF8.GetBytes(header);
- memStream.Write(headerbytes, , headerbytes.Length);
- memStream.Write(endBoundary, , endBoundary.Length);
- request.ContentLength = memStream.Length;
- Stream requestStream = request.GetRequestStream();
- memStream.Position = ;
- var tempBuffer = new byte[memStream.Length];
- memStream.Read(tempBuffer, , tempBuffer.Length);
- memStream.Close();
- requestStream.Write(tempBuffer, , tempBuffer.Length);
- requestStream.Close();
- /*string s = System.Text.Encoding.UTF8.GetString(tempBuffer, 0, tempBuffer.Length);
- Console.WriteLine(s);*/
- HttpWebResponse response = (HttpWebResponse)request.GetResponse();
- StreamReader sr = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding("UTF-8"));//("gb2312"));
- resultInfo = sr.ReadToEnd();
实现的是传递两个json串
浏览器原生 form 表单POST 数据的两种方式的更多相关文章
- Form表单提交数据的几种方式
一.submit提交 在form标签中添加Action(提交的地址)和method(post),且有一个submit按钮(<input type='submit'>)就可以进行数据的提交, ...
- 获取form表单元素值的4种方式
<html><head><title></title><script type="text/javascript"> f ...
- form 表单提交的另一种方式 js
<html> <head> <script type="text/javascript"> function formSubmit() { fm ...
- js模拟form表单提交数据, js模拟a标签点击跳转,避开使用window.open引起来的浏览器阻止问题
js模拟form表单提交数据, js模拟a标签点击跳转,避开使用window.open引起来的浏览器阻止问题 js模拟form表单提交数据源码: /** * js模拟form表单提交 * @param ...
- 关于AJAX与form表单提交数据的格式
一 form表单传输文件的格式: 只有三种: multipart/form-data 一般用于传输文件,图片文件或者其他的. 那么其中我们默认的是application/x-www-form-urle ...
- django做form表单的数据验证
我们之前写的代码都没有对前端input框输入的数据做验证,我们今天来看下,如果做form表单的数据的验证 在views文件做验证 首先用文字描述一下流程 1.在views文件中导入forms模块 2. ...
- thinkPHP5.0使用form表单提交数据和删除文章,不用TP的提示页面,使用弹出提示信息
form表单提交数据和删除文章时,TP的默认信息提示页面的看起来不是很好看,想要实现弹窗提示怎么做呢? 前端:可以使用前端的一个知识--iframe,iframe元素会创建包含另外一个文档的内联框架: ...
- form表单序列化数据之后,追加额外数据
form表单序列化数据之后追加额外数据多使用在js中,下面是追加额外数据的代码: <span style="font-size:18px;">$.param({'inv ...
- springboot框架中集成thymeleaf引擎,使用form表单提交数据,debug结果后台获取不到数据
springboot框架中集成thymeleaf引擎,使用form表单提交数据,debug结果后台获取不到数据 表单html: <form class="form-horizontal ...
随机推荐
- PHP CURL 中文说明
1.CURL是利用URL语法在命令行方式下工作的开源文件传输工具. 2.它被广泛应用在Unix.多种Linux发行版中.而且有DOS和Win32.Win64下的移植版本号. 3.它支持非常多协议:FT ...
- Filebeat+ELK
Filebeat+ELK filebeat是logstash的升级版,从功能上来说肯定不如logstash,但是logstah比较耗费资源: filebeat安装 暂时依托于window系统 下载fi ...
- Qt中的通用模板算法QtAlgorithms(qDeleteAll,qBinaryFind,qCountLeadingZeroBits,qPopulationCount,qFill,qSwap,qSort)
Qt在<QtAlgorithms>头文件中为我们提供了一系列的全局模板方法,这些模板方法主要用于容器操作,比如qDeleteAll().其在Qt中的声明如下: void qDeleteAl ...
- Eclipse中servlet显示无法导入javax.servlet包问题的解决方案
项目名-->右键 Property-->选择 JavaBuild Path-->选择 Add External JARs-->选择 把servlet-api.jar的路径输入即 ...
- 【python】使用python发送文本内容邮件
下面提供了一个使用python做的发送文本内容的邮件代码,能够在邮件内容中设置文字颜色,大小,换行等功能. #auther by zls #_*_coding:utf-8_*_ import sys ...
- 【python】python版本升级,从2.6.6升级到2.7.13
centos6.5系统自带了2.6.6版本的python,有时候为了项目上的需要,需要将python版本升级到2.7.13,下面介绍了如何进行升级. 说明:python从2.6升级到2.7会引发很多问 ...
- SpringBoot学习笔记(13):日志框架
SpringBoot学习笔记(13):日志框架——SL4J 快速开始 说明 SpringBoot底层选用SLF4J和LogBack日志框架. SLF4J的使用 SpringBoot的底层依赖关系 1. ...
- xutils3基本使用
根目录下新建一个类继承application,调用xUtils3初始化方法 public class AtguiguApplication extends Application { @Overrid ...
- 7-4 汉密尔顿回路(25 分) 【STL】
7-4 汉密尔顿回路(25 分) 著名的"汉密尔顿(Hamilton)回路问题"是要找一个能遍历图中所有顶点的简单回路(即每个顶点只访问 1 次).本题就要求你判断任一给定的回路是 ...
- Mac平台下的抓包神器 —— Charles
在开发界,“抓包”这个词想必大家耳熟能详.通过抓包工具,能够获取设备在网络通讯过程中的交换数据包.在 Windows 平台上,笔者使用较多的是 Fiddler 工具,但是由于 Fiddle 使用 C# ...