android 文件上传(POST方式模拟表单提交)
直接上代码
/**
* @category 上传文件至Server的方法
* @param uploadUrl 上传路径参数
* @param uploadFilePath 文件路径
* @author ylbf_dev
*/
private void uploadFile(String uploadUrl,String uploadFilePath) {
String end = "\r\n";
String twoHyphens = "--";
String boundary = "******";
try {
URL url = new URL(uploadUrl);
HttpURLConnection httpURLConnection = (HttpURLConnection) url.openConnection();
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
httpURLConnection.setUseCaches(false);
httpURLConnection.setRequestMethod("POST");
httpURLConnection.setRequestProperty("Connection", "Keep-Alive");
httpURLConnection.setRequestProperty("Charset", "UTF-8");
httpURLConnection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
DataOutputStream dos = new DataOutputStream(httpURLConnection.getOutputStream());
dos.writeBytes(twoHyphens + boundary + end);
dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"test.jpg\"" + end);
// dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\""
// + uploadFilePath.substring(uploadFilePath.lastIndexOf("/") + 1) + "\"" + end);
dos.writeBytes(end);
// 文件通过输入流读到Java代码中-++++++++++++++++++++++++++++++`````````````````````````
FileInputStream fis = new FileInputStream(uploadFilePath);
byte[] buffer = new byte[8192]; // 8k
int count = 0;
while ((count = fis.read(buffer)) != -1) {
dos.write(buffer, 0, count);
}
fis.close();
System.out.println("file send to server............");
dos.writeBytes(end);
dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
dos.flush();
// 读取服务器返回结果
InputStream is = httpURLConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is, "utf-8");
BufferedReader br = new BufferedReader(isr);
String result = br.readLine();
mLog.d(result);
dos.close();
is.close();
} catch (Exception e) {
e.printStackTrace();
setTitle(e.getMessage());
}
}
值得注意的是这其实就是模拟了表单提交, 就是把信息拼接到头里面 ,这里面的头信息一定要按照规范格式去写。
这是抓取到的头信息
POST http://127.0.0.1/upload.aspx HTTP/1.1
Connection: Keep-Alive
Charset: UTF-8
Content-Type: multipart/form-data;boundary=******
User-Agent: Dalvik/1.6.0 (Linux; U; Android 4.4.4; GT-I9300 Build/KTU84Q)
Host: 127.0.0.1
Accept-Encoding: gzip
Content-Length: 736640
--******
Content-Disposition: form-data; name="file"; filename="test.jpg"
关于Content-Disposition
注意这里
Content-Disposition: form-data; name="file"; filename="test.jpg"
我就遇到了不同的服务器对这里的处理识别问题,一定要写成这样 你的name 和filename按照接口要求去写,外面的双引号是必须的 虽然有些人写成了单引号 有些服务器就过去了 但是环境不一样,还是要按照规范去写。
关于boundary:
RFC文档上描述,A boundary is selected that does not occur in any of the data.意思就是选择作为boundary的数据不会出现在要上传的数据里,这一点毫无疑问,如果作为分界数据的boundary,会出现在上传的数据里,那么boundary就没有意义了~其实RCF上没有规定boundary的格式,但是大多数实现里boundary都采用了—–配合一个随机数据的方式。 我这里使用的是--******
关于multipart/form-data上传方式:
其实在封装HTTP POST上传文件的方法时,只要实现这一种即可(单个文件也可以用这种方式上传),下面上RFC上的Sample:
Content-Type: multipart/form-data, boundary=AaB03x
--AaB03x
Content-Disposition: form-data; name="field1"
Joe Blow
--AaB03x
Content-Disposition: form-data; name="pics"; filename="file1.txt"
Content-Type: text/plain
... contents of file1.txt ...
--AaB03x--
文件分界这里要切记切记切记(重要的事说三遍)
开始是--
+ boundary
String end = "\r\n";
String twoHyphens = "--";
String boundary = "******";
dos.writeBytes(twoHyphens + boundary + end);
结束的标志是--
+ boundary
+ --
,
String end = "\r\n";
String twoHyphens = "--";
String boundary = "******";
dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
在每一段信息描述后要跟一个\r\n
再跟文件数据,文件数据后面也要跟一个\r\n
,这里也是一个关键点,其他只要按照上面的Sample去实现就好了,如果Content-Type
部分不想添加根据文件后缀名填充值的话,可以直接用application/octet-stream
。
附录
RFC文档:http://www.ietf.org/rfc/rfc1867
Content-Type对照表:http://tool.oschina.net/commons