从form的enctype属性到Content-Type再到request.getInputStream()
来源:互联网 发布:服务器端口转发工具 编辑:程序博客网 时间:2024/05/17 08:33
需要实现一个手机客户端行为分析的需求,手机客户端需要上传一些数据文件。手机客户端通过http协议post方式上传数据文件的时候,我们发现在服务器端无法通过request.getInputStream()获取到相应的数据,调用request.getInputStream()读取数据里头啥都木有。
经过各种尝试我们注意到如下的情况:
1.在不做任何修改的情况下,调用request.getParameter()可以获取到部分数据,即url拼接参数的数据。
2.在不做任何修改的情况下,如果在之前任何地方都不调用request.getParameter(),而是直接调用request.getInputStream()是可以获取到数据的。
3.原来客户端使用默认的请求头Content-Type:application/x-www-form-urlencoded,修改此值为multipart/form-data或者application/octet-stream之后,通过request.getInputStream()可以获取到数据,即使之前调用过request.getParameter()。
最后的解决方法当然是客户端修改Content-Type,因为服务器端request.getInputStream()的方法不方便修改。今天具体分析下里头的原理。
【1】从form的enctype属性到Content-Type
写html的时候我们都知道form有个属性enctype,默认值是application/x-www-form-urlencoded,这个值表示会将表单数据用&符号做一个简单的拼接。例如:
POST /post_test.php HTTP/1.1 Accept-Language: zh-CN User-Agent: Mozilla/4.0 Content-Type: application/x-www-form-urlencoded Host: 192.168.12.102 Content-Length: 42 Connection: Keep-Alive Cache-Control: no-cache title=test&content=%B3%AC%BC%B6%C5%AE%C9%FA&submit=post+article
我们注意到这个时候Content-Type为application/x-www-form-urlencoded。
如果enctype的值为multipart/form-data,这个值一般用于表单中包含文件上传的情况,它会将表单中的数据使用一个boundary作为分隔上传。例如:
POST /post_test.php?t=1 HTTP/1.1 Accept-Language: zh-CN User-Agent: Mozilla/4.0 Content-Type: multipart/form-data; boundary=---------------------------7dbf514701e8 Accept-Encoding: gzip, deflate Host: 192.168.12.102 Content-Length: 345 Connection: Keep-Alive Cache-Control: no-cache -----------------------------7dbf514701e8 Content-Disposition: form-data; name="title" test -----------------------------7dbf514701e8 Content-Disposition: form-data; name="content" .... -----------------------------7dbf514701e8 Content-Disposition: form-data; name="submit" post article -----------------------------7dbf514701e8--
我们注意到这个时候Content-Type也相应的变为multipart/form-data,同时后面还加上了分隔符boundary的描述。
所以,其实form的enctype属性某种程度上决定了Content-Type值和请求body里头的数据格式。
【2】从Content-Type到request.getInputStream()
上面说到了form的处理情况,但是其实如果我们不是使用浏览器,而是自己实现的客户端来传递数据的话,这些头信息就得都由自己处理。
所以上面就出现了,上传文件的时候仍然使用了application/x-www-form-urlencoded的不标准用法。
但是为啥Content-Type会影响request的处理呢?这得从request的一些实现说起。
request.getParameter()、 request.getInputStream()、request.getReader()这三种方法是有冲突的,因为流只能被读一次。
当form表单内容采用 enctype=application/x-www-form-urlencoded编码时,先通过调用request.getParameter() 方法得到参数后,再调用 request.getInputStream()或request.getReader()已经得不到流中的内容,因为在调用 request.getParameter()时系统可能对表单中提交的数 据以流的形式读了一次,反之亦然。
当form表单内容采用 enctype=multipart/form-data编码时,即使先调用request.getParameter()也得不到数据,但是这时调用 request.getParameter()方法对 request.getInputStream()或request.getReader()没有冲突,即使已经调用了 request.getParameter()方法也 可以通过调用request.getInputStream()或request.getReader()得 到表单中的数据,而request.getInputStream()和request.getReader()在同 一个响应中是不能混合使用的,如果混合使用就会抛异常。
【3】从application/x- www-form-urlencoded到multipart/form-data
HTML中的form表单有一个关键属性 enctype=application/x-www-form-urlencoded 或multipart/form-data。
enctype=application/x- www-form-urlencoded是默认的编码方式,这种编码方式很简单,编码后的结果通常是 field1=value2&field2=value2&… 的形式,如 name=aaaa&Submit=Submit。
这种编码的具体规则可以在 rfc2231 里查到, 通常使用的表单也 是采用这种方式编码的,Servlet 的 API 提供了对这种 编码方式解码的支持,只需要调用 ServletRequest 类中的getParameter()方法就可 以得到用户表单中的字段和数据。
这种编码方式( application/x-www-form-urlencoded )虽然简单,但对于传输大块的二进制数据显得力不从心,对于传输这类数据,浏览器 采用了另一种编码方式,即 “multipart/form-data” 的编码方式,采用这种方式,浏览器可以很容易将表单内的数据和文件放在一起发送。
这种编码方式先定义好一个不可能在数据中出现的字符串作为 分界符,然后用它将各个数据段分开,而对于每个数据段都对应着 HTML 页面表单 中的一个 Input 区,包括一个 content-disposition 属性,说明了这个数据段的一些信息,如果这个数据段的内容是一个文件,还会有 Content-Type 属性,然后就是数据本身,如果以这种方式提交数据就要用request.getInputStream()或request.getReader()得到 提交的数据 ,用 request.getParameter()是得不到提交的数据的。
- 从form的enctype属性到Content-Type再到request.getInputStream()
- 从form的enctype属性到Content-Type再到request.getInputStream()
- 从form的enctype属性到Content-Type再到request.getInputStream() .
- 从form的enctype属性到Content-Type再到request.getInputStream()
- 从form的enctype属性到Content-Type再到request.getInputStream()
- 从form的enctype属性到Content-Type再到request.getInputStream()
- 从form的enctype属性到Content-Type再到request.getInputStream()
- 从form的enctype属性到Content-Type再到request.getInputStream()
- 深入解析form表单的enctype属性&从form的enctype属性到Content-Type再到request.getInputStream()
- 解决Content-Type :application/x-www-form-urlencoded 老是request.getInputStream()取不到值的问题
- 从客户端(content="<p></p>")中检测到有潜在危险的 Request.Form 值。
- 从客户端(Content="<p>测试</p>")中检测到有潜在危险的 Request.Form 值
- 错误提示 从客户端(Content="<br>测试")中检测到有潜在危险的 Request.Form 值。
- “从客户端(ctl00$Content$txtContent)中检测到有潜在危险的 Request.Form 值”之解
- mvc——从客户端(content="<p> &nb...")中检测到有潜在危险的 Request.Form
- 从客户端(content="<p>bb</p>")中检测到有潜在危险的 Request.Form 值。
- struts2开发环境中,enctype="multipart/form-data"上传文件时,request.getInputStream()为null的原因
- form标记的Enctype 属性
- AndroidManifest.xml清单文件详解--manifest节点
- 计算并输出下列的值
- VTK序列图像的读取
- Io
- 看到科技又获CES 2018创新大奖?快来高交会展位一探究竟
- 从form的enctype属性到Content-Type再到request.getInputStream()
- Linux最简单的firewalld防火墙操作流程
- 交通流理论1——发展阶段
- HTTP 请求头各字段含义
- --num 与 num-- 的陷阱
- 微软17道智力面试题及答案
- 我常使用的20个互联网工具,推荐9个给你提高工作效率
- apache ab压测与参数传递
- AndroidManifest.xml清单文件详解--application节点