Andoid - 开发实例(5):上传文件实现方法

来源:互联网 发布:创新的社会网络 编辑:程序博客网 时间:2024/05/20 11:25
一月份做项目时 Android 客户端需要上传图片,小小的研究了下,不改独享,分享!

如果要在客户端向服务器上传文件,我们就必须模拟一个POST multipart/form-data类型的请求,Content-Type必须是multipart/form-data
这篇详细介绍这个 ENCTYPE="multipart/form-data" 协议,来解决自己的Java程序向服务器传文件的问题(比如:安卓程序上传图片)

ENCTYPE="multipart/form-data" :通过 http 协议上传文件 rfc1867协议,客户端发送内容构造

<form action="picture/upload.do" method="POST" ENCTYPE="multipart/form-data">
    <input type="text" name="users_id">
    <input type="text" name="users_name">
    <input type="file" name="image_path">
    <input type="submit">
</form>
使用上面这个表单,抓包的结果如下
POST /picture/upload.do HTTP/1.1
Accept: application/x-ms-application, image/jpeg, application/xaml+xml, image/gif, image/pjpeg, application/x-ms-xbap, */*
Referer: http://192.168.1.98:8080/uploadpic.jsp
Accept-Language: zh-CN
User-Agent: Mozilla/4.0 
Content-Type: multipart/form-data; boundary=---------------------------7dd36df20300
Accept-Encoding: gzip, deflate
Host: 192.168.1.98:8080
Content-Length: 529762
Connection: Keep-Alive
Cache-Control: no-cache

-----------------------------7dd36df20300
Content-Disposition: form-data; name="users_id"
<!--空行-->
1
-----------------------------7dd36df20300
Content-Disposition: form-data; name="users_name"
<!--空行-->
admin
-----------------------------7dd36df20300
Content-Disposition: form-data; name="image_path"; filename="S21223-170317.jpg"
Content-Type: image/pjpeg
<!--空行-->
<!--文件 byte 数据-->
-----------------------------7dd36df20300--
<!--空行-->

详细解析:
Content-Type: multipart/form-data; boundary=---------------------------7dd36df20300
根据 rfc1867, multipart/form-data是必须的。
---------------------------7dd36df20300  是分隔符,分隔多个文件、表单项。
其中 d36df20300 是即时生成的一个字符,用以确保整个分隔符不会在文件或表单项的内容中出现。
---------------------------7d    IE内核标志
---------------------------71    Mozila内核标志
从请求体里可以看出每一条数据后面都有换行 \r\n ,并且 Parameter 和 value 之间还有个空行
最后把格式提取:
--分隔符 \r\n
Content-Disposition: form-data; name="[Parameter]" \r\n
\r\n
[value] \r\n
--分隔符 \r\n
Content-Disposition: form-data; name="[Parameter]"; filename="[]" \r\n
Content-Type: image/pjpeg \r\n
\r\n
<!--文件 byte 数据--> \r\n
--分隔符-- \r\n
\r\n

了解了传输格式,接下来就是程序实现:

String path = "http://192.168.1.102:8080/picture/upload.do";
// 换行符
String enter = "\r\n";
// 分割线
String boundary = "---------------------------7dd36df20300";
StringBuffer sb = new StringBuffer();
// 获取文件流
File file = new File("D:\\123.jpg");
FileInputStream is = new FileInputStream(file);
// 参数信息
String[] keys = { "users_id", "users_name" };
String[] values = { "1", "admin" };
// 拼凑参数
for (int i = 0; i < keys.length; i++) {
    sb.append("--" + boundary + enter);
    sb.append("Content-Disposition: form-data; name=\"" + keys[i] + "\"");
    sb.append(enter + enter);
    sb.append(values[i]);
    sb.append(enter);
}
// 拼凑文件头部信息
sb.append("--" + boundary);
sb.append(enter);
sb.append("Content-Disposition: form-data; name=\"image_path\"; filename=\"123.jpg\"");
sb.append(enter);
sb.append("Content-Type: image/*");
sb.append(enter + enter);
byte[] data = sb.toString().getBytes();
byte[] end_data = (enter + "--" + boundary + "--" + enter + enter).getBytes();
// 初始化 HttpURLConnection
URL url = new URL(path);
HttpURLConnection con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(3000);
con.setDoInput(true);
con.setDoOutput(true);
con.setUseCaches(false);
con.setRequestMethod("POST");
con.setRequestProperty("Connection", "Keep-Alive");
con.setRequestProperty("Charset", "UTF-8");
con.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
con.setRequestProperty("Content-Length", file.length() + data.length 
+ end_data.length + "");
// 开始上传
OutputStream outputStream = con.getOutputStream();
outputStream.write(data);
byte[] fileBuffer = new byte[1024];
int length = -1;
while ((length = is.read(fileBuffer)) != -1) {
    outputStream.write(fileBuffer, 0, length);
}
is.close();
outputStream.write(end_data);
outputStream.flush();
outputStream.close();
con.getResponseCode();



原创粉丝点击