JAVA模拟HTTP post请求上传文件
在开发中,我们使用的比较多的HTTP请求方式基本上就是GET、POST。其中GET用于从服务器获取数据,POST主要用于向服务器提交一些表单数据,例如文件上传等。而我们在使用HTTP请求时中遇到的比较麻烦的事情就是构造文件上传的HTTP报文格式,这个格式虽说也比较简单,但也比较容易出错。今天我们就一起来学习HTTP POST的报文格式以及通过Java来模拟文件上传的请求。
首先我们来看一个POST的报文请求,然后我们再来详细的分析它。
POST报文格式
- POST /api/feed/ HTTP/1.1
- Accept-Encoding: gzip
- Content-Length: 225873
- Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
- Host: www.myhost.com
- Connection: Keep-Alive
- --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
- Content-Disposition: form-data; name="lng"
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- 116.361545
- --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
- Content-Disposition: form-data; name="lat"
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- 39.979006
- --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
- Content-Disposition: form-data; name="images"; filename="/storage/emulated/0/Camera/jdimage/1xh0e3yyfmpr2e35tdowbavrx.jpg"
- Content-Type: application/octet-stream
- Content-Transfer-Encoding: binary
- 这里是图片的二进制数据
- --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp--
这里我们提交的是经度、纬度和一张图片(图片数据比较长,而且比较杂乱,这里省略掉了)。
格式分析
请求头分析
- POST /api/feed/ HTTP/1.1
这一行就说明了这个请求的请求方式,即为POST方式,要请求的子路径为/api/feed/,例如我们的服务器地址为www.myhost.com,然后我们的这个请求的完整路径就是www.myhost.com/api/feed/,最后说明了HTTP协议的版本号为1.1。
- Accept-Encoding: gzip
- Content-Length: 225873
- Content-Type: multipart/form-data; boundary=OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
- Host: www.myhost.com
- Connection: Keep-Alive
这几个header的意思分别为服务器返回的数据需要使用gzip压缩、请求的内容长度为225873、内容的类型为"multipart/form-data"、请求参数分隔符(boundary)为OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp、请求的根域名为www.myhost.com、HTTP连接方式为持久连接( Keep-Alive)。
- --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
不管boundary本身有没有这个"--",这个"--"都是不能省略的。
我们知道HTTP协议采用“请求-应答”模式,当使用普通模式,即非KeepAlive模式时,每个请求/应答客户和服务器都要新建一个连接,完成之后立即断开连接(HTTP协议为无连接的协议);当使用Keep-Alive模式(又称持久连接、连接重用)时,Keep-Alive功能使客户端到服务器端的连接持续有效,当出现对服务器的后续请求时,Keep-Alive功能避免了建立或者重新建立连接。
如上图中,左边的是关闭Keep-Alive的情况,每次请求都需要建立连接,然后关闭连接;右边的则是Keep-Alive,在第一次建立请求之后保持连接,然后后续的就不需要每次都建立、关闭连接了,启用Keep-Alive模式肯定更高效,性能更高,因为避免了建立/释放连接的开销。
http 1.0中默认是关闭的,需要在http头加入"Connection: Keep-Alive",才能启用Keep-Alive;http 1.1中默认启用Keep-Alive,如果加入"Connection: close ",才关闭。目前大部分浏览器都是用http1.1协议,也就是说默认都会发起Keep-Alive的连接请求了,所以是否能完成一个完整的Keep- Alive连接就看服务器设置情况。
请求实体分析
- --OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp
- Content-Disposition: form-data; name="lng"
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- 116.361545
上面第一行为--OCqxMF6-JxtxoMDHmoG5W5eY9MGRsTBp,也就是--加上boundary内容,最后加上一个换行 (这个换行不能省略),换行的字符串表示为"\r\n"。第二行为Content-Disposition和参数名,这里的参数名为lng,即经度。Content-Disposition就是当用户想把请求所得的内容存为一个文件的时候提供一个默认的文件名,这里我们不过多关注。第三行为Content-Type,即WEB 服务器告诉浏览器自己响应的对象的类型,还有指定字符编码为UTF-8。第四行是描述的是消息请求(request)和响应(response)所附带的实体对象(entity)的传输形式,简单文本数据我们设置为8bit,文件参数我们设置为binary就行。然后添加两个换行之后才是参数的具体内容。例如这里的参数内容为116.361545。
- Content-Type: text/plain; charset=UTF-8
- Content-Transfer-Encoding: 8bit
- Content-Type: application/octet-stream
- Content-Transfer-Encoding: binary
模拟文件上传请求
- public static void uploadFile(String fileName) {
- try {
- // 换行符
- final String newLine = "\r\n";
- final String boundaryPrefix = "--";
- // 定义数据分隔线
- String BOUNDARY = "========7d4a6d158c9";
- // 服务器的域名
- URL url = new URL("www.myhost.com");
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- // 设置为POST情
- conn.setRequestMethod("POST");
- // 发送POST请求必须设置如下两行
- conn.setDoOutput(true);
- conn.setDoInput(true);
- conn.setUseCaches(false);
- // 设置请求头参数
- conn.setRequestProperty("connection", "Keep-Alive");
- conn.setRequestProperty("Charsert", "UTF-8");
- conn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
- OutputStream out = new DataOutputStream(conn.getOutputStream());
- // 上传文件
- File file = new File(fileName);
- StringBuilder sb = new StringBuilder();
- sb.append(boundaryPrefix);
- sb.append(BOUNDARY);
- sb.append(newLine);
- // 文件参数,photo参数名可以随意修改
- sb.append("Content-Disposition: form-data;name=\"photo\";filename=\"" + fileName
- + "\"" + newLine);
- sb.append("Content-Type:application/octet-stream");
- // 参数头设置完以后需要两个换行,然后才是参数内容
- sb.append(newLine);
- sb.append(newLine);
- // 将参数头的数据写入到输出流中
- out.write(sb.toString().getBytes());
- // 数据输入流,用于读取文件数据
- DataInputStream in = new DataInputStream(new FileInputStream(
- file));
- byte[] bufferOut = new byte[1024];
- int bytes = 0;
- // 每次读1KB数据,并且将文件数据写入到输出流中
- while ((bytes = in.read(bufferOut)) != -1) {
- out.write(bufferOut, 0, bytes);
- }
- // 最后添加换行
- out.write(newLine.getBytes());
- in.close();
- // 定义最后数据分隔线,即--加上BOUNDARY再加上--。
- byte[] end_data = (newLine + boundaryPrefix + BOUNDARY + boundaryPrefix + newLine)
- .getBytes();
- // 写上结尾标识
- out.write(end_data);
- out.flush();
- out.close();
- // 定义BufferedReader输入流来读取URL的响应
- // BufferedReader reader = new BufferedReader(new InputStreamReader(
- // conn.getInputStream()));
- // String line = null;
- // while ((line = reader.readLine()) != null) {
- // System.out.println(line);
- // }
- } catch (Exception e) {
- System.out.println("发送POST请求出现异常!" + e);
- e.printStackTrace();
- }
- }
JAVA模拟HTTP post请求上传文件的更多相关文章
- Java模拟表单POST上传文件
JAVA模拟表单POST上传文件 import java.awt.image.BufferedImage;import java.awt.image.ColorModel;import java.io ...
- Java模拟客户端向服务器上传文件
先来了解一下客户端与服务器Tcp通信的基本步骤: 服务器端先启动,然后启动客户端向服务器端发送数据. 服务器端收到客户端发送的数据,服务器端会响应应客户端,向客户端发送响应结果. 客户端读取服务器发送 ...
- C#模拟HTTP Form请求上传文件
using System; using System.Collections.Generic; using System.Text; using System.Net; using System.IO ...
- Java客户端通过Http发送POST请求上传文件到web服务器
http://www.cnblogs.com/WilliamJiang/archive/2012/04/29/2475883.html 1.朋友的一个需求,让我给他实现,需求是这样的,需要用ASP.n ...
- SpringMVC实现PUT请求上传文件
在JQuery中,我们可以进行REST ful中delete和put的请求,但是在java EE标准中,默认只有在POST请求的时候,servlet 才会通过getparameter()方法取得请求体 ...
- SSM框架下,使用ajax请求上传文件(doc\docx\excel\图片等)
1.准备工作 1.1.添加上传必要jar包 <dependency> <groupId>commons-io</groupId> <artifactId> ...
- Postman Post请求上传文件
Postman Post请求上传文件一.选择post请求方式,输入请求地址 二.填写Headers Key:Content-Type :Value:multipart/form-data 如下图 三. ...
- python中使用multipart/form-data请求上传文件
最近测试的接口是上传文件的接口,上传单个文件,我主要使用了2种方法~ 接口例如: URL: http://www.baidu.com/*** method:post 参数: { "salar ...
- element-ui上传组件,通过自定义请求上传文件
记录使用element-ui上传组件,通过自定义请求上传文件需要注意的地方. <el-upload ref="uploadMutiple" :auto-upload=&quo ...
随机推荐
- 设置glassfish开启自动domain
1-在/etc/rc.local中配置开机自启动 su - sumapay25 -c "/opt/glassfish.sh start 1" 2-/opt/glassfish.sh ...
- ios开发证书
文章写得很透彻 https://segmentfault.com/a/1190000004144556?f=tt&hmsr=toutiao.io
- JS Util1(basic)
1.
- 跟着思维导图学习javascript
1.javascript 变量 2.javascript 运算符 3.javascript 数组 4.javascript 流程语句 5.javascript字符串函数 6.javascript 函数 ...
- 【转】Win8下安装SQL Server 2005无法启动服务
安装了Windows8,但是发现不支持Sql Server 2005的安装.网上找了很多办法,基本上都有缺陷.现在终于找到一种完全正常没有缺陷的办法了,和大家分享一下. 1.正常安装任一版本的SQL ...
- [转]IntelliJ IDEA 使用心得与常用快捷键
IntelliJ IDEA 使用心得与常用快捷键 那种酸爽,根本说不出来—————————————————————————— by: Jimi没有BondJimi是谁? 就是洒家啊! 刚开始学习写Ja ...
- 纪勇破解QQ号问题
试题描述 来到了新学校,才相处不到一个月,jy就对oyjy一见钟情.于是向oyjy问QQ号.当然身为创(实)新(验)一班的同学,oyjy还是要考考jy.她给了纪勇一个加密后的QQ号,让纪勇解密,解密规 ...
- 图说js中的this——深入理解javascript中this指针
没搞错吧!js写了那么多年,this还是会搞错!没搞错,javascript就是回搞错! ………… 文章来源自——周陆军的个人网站:http://zhoulujun.cn/zhoulujun/html ...
- workbench中safe update
1.在workbench中表格显示为readonly ,更新时提示Error Code: 1175. You are using safe update mode and you tried to u ...
- Window Azure ServiceBus Messaging消息队列技术系列2-编程SDK入门
各位,上一篇基本概念和架构中,我们介绍了Window Azure ServiceBus的消息队列技术的概览.接下来,我们进入编程模式和详细功能介绍模式,一点一点把ServiceBus技术研究出来. 本 ...