通过构造基于 HTTP 协议的传输内容实现图片自动上传到服务器功能 。如果自己编码构造 HTTP 协议,那么编写的代码质量肯定不高,建议模仿 HttpClient
.zip examples
\mime\ClientMultipartFormPost.java 来实现,并通过源码来进一步理解如何优雅高效地构造 HTTP 协议传输内容。
自己构造 HTTP
协议传输内容的想法,从何而来呢?灵感启迪于这篇博文“Android下的应用编程——用HTTP协议实现文件上传功能
”,以前从未想过通过抓取
HTTP 请求数据格式,根据协议自己构造数据来实现数据提交。哎,Out 了。因为 Apache HttpClient
框架就是通过此方式来实现的,以前从未注意到,看来以后要多多向前人学习啊!结果是:阅读了此框架的源码后,才知道自己编写的代码和人家相比真不是一个档次的。现在已经下定决心了,多读开源框架代码,不但可以熟悉相关业务流程,而且还可以学到设计模式在实际业务需求中的应用,更重要的是领悟其中的思想。业务流程、实践能力、框架思想,一举三得,何乐而不为呢。^_^
test.html 部分源码:
<form action="Your_Action_Url
" method="post" enctype="multipart/form-data
" name="form1" id="form1">
<p>
<label for="upload_file"></label>
<input type="file" name="upload_file" id="upload_file
" />
</p>
<p>
<input type="submit" name="action" id="action
" value="upload
" />
</p>
</form>
通过 HttpWatch 查看抓取到的包数据格式:
下面将分别通过按照 HttpWatch 抓取下来的协议格式内容构造传输内容实现文件上传功能和基于 HttpClient 框架实现文件上传功能。
项目配置目录Your_Project/config
,相关文件
如下:
actionUrl.properties 文件内容:
Your_Action_Url
formDataParams.properties 文件内容(对应 HTML Form 属性内容):
action
=upload
imageParams.properties 文件内容(这里文件路径已配置死了,不好!建议在程序中动态设置,即通过传入相关参数实现。):
upload_file
=images/roewe.jpg
MIMETypes.properties 文件内容(参考自 Multimedia MIME Reference
):
jpeg:image/jpeg
jpg:image/jpeg
png:image/png
gif:image/gif
1. 在《Android下的应用编程——用HTTP协议实现文件上传功能
》代码的基础上,通过进一步改进得到如下代码(Java、Android 都可以 run):
/**
* 文件名称:UploadImage.java
*
* 版权信息:Apache License, Version 2.0
*
* 功能描述:实现图片文件上传。
*
* 创建日期:2011-5-10
*
* 作者:Bert Lee
*/
/*
* 修改历史:
*/
public class UploadImage {
String multipart_form_data = "multipart/form-data";
String twoHyphens = "--";
String boundary = "****************fD4fH3gL0hK7aI6"; // 数据分隔符
String lineEnd = System.getProperty("line.separator"); // The value is "\r\n" in Windows.
/*
* 上传图片内容,格式请参考HTTP 协议格式。
* 人人网Photos.upload中的”程序调用“http://wiki.dev.renren.com/wiki/Photos.upload#.E7.A8.8B.E5.BA.8F.E8.B0.83.E7.94.A8
* 对其格式解释的非常清晰。
* 格式如下所示:
* --****************fD4fH3hK7aI6
* Content-Disposition: form-data; name="upload_file"; filename="apple.jpg"
* Content-Type: image/jpeg
*
* 这儿是文件的内容,二进制流的形式
*/
private void addImageContent(Image[] files, DataOutputStream output) {
for(Image file : files) {
StringBuilder split = new StringBuilder();
split.append(twoHyphens + boundary + lineEnd);
split.append("Content-Disposition: form-data; name=\"" + file.getFormName() + "\"; filename=\"" + file.getFileName() + "\"" + lineEnd);
split.append("Content-Type: " + file.getContentType() + lineEnd);
split.append(lineEnd);
try {
// 发送图片数据
output.writeBytes(split.toString());
output.write(file.getData(), 0, file.getData().length);
output.writeBytes(lineEnd);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
/*
* 构建表单字段内容,格式请参考HTTP 协议格式(用FireBug可以抓取到相关数据)。(以便上传表单相对应的参数值)
* 格式如下所示:
* --****************fD4fH3hK7aI6
* Content-Disposition: form-data; name="action"
* // 一空行,必须有
* upload
*/
private void addFormField(Set<Map.Entry<Object,Object>> params, DataOutputStream output) {
StringBuilder sb = new StringBuilder();
for(Map.Entry<Object, Object> param : params) {
sb.append(twoHyphens + boundary + lineEnd);
sb.append("Content-Disposition: form-data; name=\"" + param.getKey() + "\"" + lineEnd);
sb.append(lineEnd);
sb.append(param.getValue() + lineEnd);
}
try {
output.writeBytes(sb.toString());// 发送表单字段数据
} catch (IOException e) {
throw new RuntimeException(e);
}
}
/**
* 直接通过 HTTP 协议提交数据到服务器,实现表单提交功能。
* @param actionUrl 上传路径
* @param params 请求参数key为参数名,value为参数值
* @param files 上传文件信息
* @return 返回请求结果
*/
public String post(String actionUrl, Set<Map.Entry<Object,Object>> params, Image[] files) {
HttpURLConnection conn = null;
DataOutputStream output = null;
BufferedReader input = null;
try {
URL url = new URL(actionUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(120000);
conn.setDoInput(true); // 允许输入
conn.setDoOutput(true); // 允许输出
conn.setUseCaches(false); // 不使用Cache
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "keep-alive");
conn.setRequestProperty("Content-Type", multipart_form_data + "; boundary=" + boundary);
conn.connect();
output = new DataOutputStream(conn.getOutputStream());
addImageContent(files, output); // 添加图片内容
addFormField(params, output); // 添加表单字段内容
output.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);// 数据结束标志
output.flush();
int code = conn.getResponseCode();
if(code != 200) {
throw new RuntimeException("请求‘" + actionUrl +"’失败!");
}
input = new BufferedReader(new InputStreamReader(conn.getInputStream()));
StringBuilder response = new StringBuilder();
String oneLine;
while((oneLine = input.readLine()) != null) {
response.append(oneLine + lineEnd);
}
return response.toString();
} catch (IOException e) {
throw new RuntimeException(e);
} finally {
// 统一释放资源
try {
if(output != null) {
output.close();
}
if(input != null) {
input.close();
}
} catch (IOException e) {
throw new RuntimeException(e);
}
if(conn != null) {
conn.disconnect();
}
}
}
public static void main(String[] args) {
try {
String response = "";
BufferedReader in = new BufferedReader(new FileReader("config/actionUrl.properties"));
String actionUrl = in.readLine();
// 读取表单对应的字段名称及其值
Properties formDataParams = new Properties();
formDataParams.load(new FileInputStream(new File("config/formDataParams.properties")));
Set<Map.Entry<Object,Object>> params = formDataParams.entrySet();
// 读取图片所对应的表单字段名称及图片路径
Properties imageParams = new Properties();
imageParams.load(new FileInputStream(new File("config/imageParams.properties")));
Set<Map.Entry<Object,Object>> images = imageParams.entrySet();
Image[] files = new Image[images.size()];
int i = 0;
for(Map.Entry<Object,Object> image : images) {
Image file = new Image(image.getValue().toString(), image.getKey().toString());
files[i++] = file;
}
// Image file = new Image("images/apple.jpg", "upload_file");
// Image[] files = new Image[0];
// files[0] = file;
response = new UploadImage().post(actionUrl, params, files);
System.out.println("返回结果:" + response);
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 基于 HttpClient 框架实现文件上传,实例代码如下:
/**
* 文件名称:ClientMultipartFormPost.java
*
* 版权信息:Apache License, Version 2.0
*
* 功能描述:通过 HttpClient 4.1.1 实现文件上传。
*
* 创建日期:2011-5-15
*
* 作者:Bert Lee
*/
/*
* 修改历史:
*/
public class ClientMultipartFormPost {
/**
* 直接通过 HttpMime's MultipartEntity 提交数据到服务器,实现表单提交功能。
* @return Post 请求所返回的内容
*/
public static String filePost() {
HttpClient httpclient = new DefaultHttpClient();
try {
BufferedReader in = new BufferedReader(new FileReader("config/actionUrl.properties"));
String actionUrl;
actionUrl = in.readLine();
HttpPost httppost = new HttpPost(actionUrl);
// 通过阅读源码可知,要想实现图片上传功能,必须将 MultipartEntity 的模式设置为 BROWSER_COMPATIBLE 。
MultipartEntity multiEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
// MultipartEntity multiEntity = new MultipartEntity();
// 读取图片的 MIME Type 类型集
Properties mimeTypes = new Properties();
mimeTypes.load(new FileInputStream(new File("config/MIMETypes.properties")));
// 构造图片数据
Properties imageParams = new Properties();
imageParams.load(new FileInputStream(new File("config/imageParams.properties")));
String fileType;
for(Map.Entry<Object,Object> image : imageParams.entrySet()) {
String path = image.getValue().toString();
fileType = path.substring(path.lastIndexOf(".") + 1);
FileBody binaryContent = new FileBody(new File(path), mimeTypes.get(fileType).toString());
// FileBody binaryContent = new FileBody(new File(path));
multiEntity.addPart(image.getKey().toString(), binaryContent);
}
// 构造表单参数数据
Properties formDataParams = new Properties();
formDataParams.load(new FileInputStream(new File("config/formDataParams.properties")));
for(Entry<Object, Object> param : formDataParams.entrySet()) {
multiEntity.addPart(param.getKey().toString(), new StringBody(param.getValue().toString()));
}
httppost.setEntity(multiEntity);
// Out.println("executing request " + httppost.getRequestLine());
HttpResponse response = httpclient.execute(httppost);
HttpEntity resEntity = response.getEntity();
// Out.println("-------------------");
// Out.println(response.getStatusLine());
if(resEntity != null) {
String returnContent = EntityUtils.toString(resEntity);
EntityUtils.consume(resEntity);
return returnContent; // 返回页面内容
}
} catch (IOException e) {
e.printStackTrace();
} finally {
// 释放资源
httpclient.getConnectionManager().shutdown();
}
return null;
}
// 测试
public static void main(String[] args) {
Out.println("Response content: " + ClientMultipartFormPost.filePost());
}
}
参考资料:
分享到:
相关推荐
Android模拟 HTTP multipart/form-data 请求协议信息实现图片上传
在IT行业中,网络通信是不可或缺的一部分,而上传文件或发送包含多个部分的数据通常涉及使用`multipart/form-data`编码方式。`multipart/form-data`是一种HTTP请求的Content-Type,它允许我们发送一个请求体,其中...
在本主题中,我们将深入探讨如何使用C#来模拟POST请求,以便发送JSON和multipart/form-data格式的数据。这两种数据格式在现代网络应用中非常常见,特别是用于API交互和文件上传。 首先,让我们了解JSON(JavaScript...
在Web开发中,文件上传是一项常见的功能,而`multipart/form-data`是一种HTTP协议中用于处理表单数据,尤其是包含文件上传的表单数据的编码方式。这篇博客文章可能探讨了如何利用这种编码类型来实现文件上传,并且...
用C语言实现multipart/form-data文件上传,没有用到curl之类的库。之前做个小的日志上传程序写的。
当我们需要上传文件或同时发送键值对(包括复杂的数据结构如JSON)时,通常会使用`multipart/form-data`和JSON这两种数据格式。下面我们将深入探讨如何在C#中实现这两种数据格式的POST请求。 一、`multipart/form-...
"multipart/form-data" 是一种HTTP协议中的数据编码方式,主要用于在表单提交时上传文件,如图片或视频。本教程将深入讲解如何利用 Indy 10 库中的 `TIdHTTP` 控件来实现这一功能。 首先,你需要确保已经安装了Indy...
使用c#实现的HttpClient拼接multipart/form-data形式参数post提交数据,包含图片内容,有需要的可以下载,希望能帮到有需要的人,
在探讨“解决当FORM的ENCTYPE='multipart/form-data'时request.getParameter()获取不到值的方法”这一主题时,我们首先需要理解为什么在特定情况下,传统的`request.getParameter()`方法无法正常工作,以及如何通过...
Apache Commons IO是处理IO操作的工具集,而Commons Fileupload则是专门用来处理文件上传的库,它可以方便地处理`multipart/form-data`编码的表单数据。 以下是关于这个话题的详细知识点: 1. **HTML表单与文件...
综上所述,WebAPIFileUploadDemo项目为理解并实现基于`multipart/form-data`的文件和数据上传提供了一个基础模板。它展示了从客户端构建请求到服务器端解析和处理数据的完整流程,帮助开发者在实际项目中实现类似...
在实际项目中,这样的应用可能会用到上述的`multipart/form-data`(用于上传文件)和JSON(用于传递用户信息或文件元数据)技术。 总的来说,理解和熟练运用`multipart/form-data`和JSON数据格式在C#中的处理,对于...
### 解决Java enctype "multipart/form-data" 文件上传...综上所述,理解并掌握`multipart/form-data`的工作原理及其在Java Web应用中的实现细节是非常重要的。这有助于开发者更高效地解决实际项目中的文件上传问题。
这是因为`multipart/form-data`允许在请求中携带二进制数据,如图片、文档等文件。然而,这种编码方式下,常规的`request.getParameter()`方法无法正确地获取到表单中的文本字段值,因为这些值被封装在了请求的多...
在Web开发中,`multipart/form-data`是一种用于发送表单数据的编码类型,尤其适用于处理文件上传。此编码方式能够使客户端浏览器将表单中的普通文本字段与文件字段一起发送到服务器端进行处理。 #### 标题解析 - **...
在C#中,可以使用HttpWebRequest和HttpWebResponse类来实现multipart/form-data方式上传附件与请求参数。首先,需要创建一个HttpWebRequest对象,并设置其Method属性为“POST”,ContentType属性为“multipart/form-...
1. **限制上传大小**:限制通过`multipart/form-data`提交的数据大小,防止大文件上传导致的资源耗尽。可以在PHP配置文件(php.ini)中设置`post_max_size`和`upload_max_filesize`来限制上传文件的大小。 2. **...
在Python的网络编程中,处理HTTP请求是常见的任务,尤其是涉及到文件上传时,multipart/form-data是一种标准的HTTP请求格式。本文将详细介绍如何使用Python的requests库处理multipart/form-data类型的请求。 首先,...
servlet上传 enctype="multipart/form-data" servlet上传 enctype="multipart/form-data