使用浏览器上传文件,然后通过Wireshark抓包分析,发现发送的数据大概是这个样子。

MIME Multipart Media Encapsulation, Type: multipart/form-data, Boundary: "----WebKitFormBoundary1UBMMKIkN58civN4"
[Type: multipart/form-data]
First boundary: ------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part:
Content-Disposition: form-data; name="name"\r\n\r\n
Data (16 bytes)
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part: (image/png)
Content-Disposition: form-data; name="photo[]"; filename="Screenshot (2).png"\r\n
Content-Type: image/png\r\n\r\n
Portable Network Graphics
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part: (image/png)
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part: (image/png)
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part: (image/png)
Boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4\r\n
Encapsulated multipart part: (image/png)
Last boundary: \r\n------WebKitFormBoundary1UBMMKIkN58civN4--\r\n

 首先来自定义一个HttpEntity,

package cc.dewdrop.volleydemo.utils;

import com.android.volley.VolleyLog;

import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.message.BasicHeader; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.Closeable;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import javax.activation.MimetypesFileTypeMap; /**
* Created by Tingkuo on 12/1/2015.
*/
public class FileUploadEntity implements HttpEntity { private static final String TAG = FileUploadEntity.class.getSimpleName(); private static final String BOUNDARY = "__FILE_UPLOAD_ENTITY__"; private ByteArrayOutputStream mOutputStream; public FileUploadEntity() {
mOutputStream = new ByteArrayOutputStream(); try {
writeFirstBoundary();
} catch (IOException e) {
e.printStackTrace();
}
} private void writeFirstBoundary() throws IOException {
VolleyLog.e("writeFirstBoundary");
mOutputStream.write(("--" + BOUNDARY + "\r\n").getBytes());
mOutputStream.write(("Content-Disposition: form-data; name=\"" + "name" + "\"\r\n\r\n").getBytes());
mOutputStream.write("Content-Transfer-Encoding: binary\n\n".getBytes());
mOutputStream.flush();
} private void writeLastBoundary() throws IOException {
VolleyLog.e("writeLastBoundary");
mOutputStream.write(("\r\n--" + BOUNDARY + "--\r\n").getBytes());
} public void addFile(final String key, final File file) {
VolleyLog.e("addFile");
InputStream inputStream = null; try {
mOutputStream.write(("\r\n--" + BOUNDARY + "\r\n").getBytes()); StringBuilder stringBuilderContentDisposition = new StringBuilder();
stringBuilderContentDisposition.append("Content-Disposition: ");
stringBuilderContentDisposition.append("form-data; ");
stringBuilderContentDisposition.append("name=\"" + key + "\"; ");
stringBuilderContentDisposition.append("filename=\"" + file.getName() + "\"\r\n");
mOutputStream.write(stringBuilderContentDisposition.toString().getBytes()); StringBuilder stringBuilderContentType = new StringBuilder();
stringBuilderContentType.append("Content-Type: ");
stringBuilderContentType.append(new MimetypesFileTypeMap().getContentType(file).toString());
stringBuilderContentType.append("\r\n\r\n");
mOutputStream.write(stringBuilderContentType.toString().getBytes()); inputStream = new FileInputStream(file);
final byte[] buffer = new byte[1024];
int len = 0;
while ((len = inputStream.read(buffer)) != -1) {
VolleyLog.e("len --> %s", String.valueOf(len));
mOutputStream.write(buffer, 0, len);
}
VolleyLog.e("===last====len --> %s", String.valueOf(len)); mOutputStream.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeSilently(inputStream);
}
} private void closeSilently(Closeable closeable) {
try {
if (closeable != null) {
closeable.close();
}
} catch (final IOException e) {
e.printStackTrace();
}
} @Override
public boolean isRepeatable() {
return false;
} @Override
public boolean isChunked() {
return false;
} @Override
public long getContentLength() {
return mOutputStream.toByteArray().length;
} @Override
public Header getContentType() {
return new BasicHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
} @Override
public Header getContentEncoding() {
return null;
} @Override
public InputStream getContent() throws IOException, UnsupportedOperationException {
return new ByteArrayInputStream(mOutputStream.toByteArray());
} @Override
public void writeTo(OutputStream outputStream) throws IOException {
writeLastBoundary();
outputStream.write(mOutputStream.toByteArray());
} @Override
public boolean isStreaming() {
return false;
} @Override
public void consumeContent() throws IOException { }
}

现在来解释一下,首先这是支持多文件上传的,数据格式一共包括四部分,Content-Type,First boundary,文件二进制数据[],及Last boundary。可以有多个文件,使用addFile方法插入,文件之间需要有分隔符Boundary。每个文件需要有Content-Disposition及Content-Type

然后再自定义一个Request,根据需要使用不同的构造方法

package cc.dewdrop.volleydemo.utils;

import com.android.volley.AuthFailureError;
import com.android.volley.NetworkResponse;
import com.android.volley.Request;
import com.android.volley.Response;
import com.android.volley.Response.Listener;
import com.android.volley.Response.ErrorListener;
import com.android.volley.toolbox.HttpHeaderParser; import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.Map; /**
* Created by Tingkuo on 12/2/2015.
*/
public class FileUploadRequest extends Request<String> {
private final Listener<String> mListener; private FileUploadEntity mFileUploadEntity = new FileUploadEntity();
private Map<String, String> mHeaders = new HashMap<>(); public FileUploadRequest(String url, Listener<String> listener) {
this(url, listener, null);
} public FileUploadRequest(String url, Listener<String> listener, ErrorListener errorListener) {
this(Method.POST, url, listener, errorListener);
} public FileUploadRequest(int method, String url, Listener<String> listener, ErrorListener errorListener) {
super(method, url, errorListener);
this.mListener = listener;
} public FileUploadEntity getFileUploadEntity() {
return mFileUploadEntity;
} @Override
public String getBodyContentType() {
return mFileUploadEntity.getContentType().getValue();
} public void addHeader(String key, String value) {
mHeaders.put(key, value);
} @Override
public Map<String, String> getHeaders() throws AuthFailureError {
return mHeaders;
} @Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
try {
mFileUploadEntity.writeTo(outputStream);
} catch (IOException e) {
e.printStackTrace();
}
return outputStream.toByteArray();
} @Override
protected Response<String> parseNetworkResponse(NetworkResponse response) {
String parsed = "";
try {
parsed = new String(response.data, HttpHeaderParser.parseCharset(response.headers));
} catch (UnsupportedEncodingException e) {
parsed = new String(response.data);
}
return Response.success(parsed, HttpHeaderParser.parseCacheHeaders(response));
} @Override
protected void deliverResponse(String response) {
if (mListener != null) {
mListener.onResponse(response);
}
}
}

代码是放在Volley中其他类型Request来写的,没什么好说的。

最后就是如何调用

    private void simpleUploadFile() {
File file = new File(Environment.getExternalStorageDirectory().getPath() + "/upload.png"); fileUploadRequest = new FileUploadRequest(
Request.Method.POST,
urlList.get(2),
new Response.Listener<String>() {
@Override
public void onResponse(String response) {
textViewInfo.setText("Post Succeed:\n" + response.replace("<br>", "\n"));
Log.e(TAG, response);
dialog.dismiss();
}
},
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
textViewInfo.setText("Post Failed:\n" + error.getMessage());
Log.e(TAG, error.getMessage());
dialog.dismiss();
}
}
);
fileUploadRequest.addHeader("User-Agent", "Android 5.1.1");
FileUploadEntity fileUploadEntity = fileUploadRequest.getFileUploadEntity();
fileUploadEntity.addFile("file[]", file);
fileUploadEntity.addFile("file[]", file);
fileUploadEntity.addFile("file[]", file);
fileUploadEntity.addFile("file[]", file);
fileUploadEntity.addFile("file[]", file);
requestQueue.add(fileUploadRequest); dialog.show();
}

实例化一个新的Request对象,传入Method,Url,然后通过Request对象来获取Entity,通过addFile()方法来传入需要上传的文件,最后加入requestQueue,使用方法与其他类型Request相同。

备注:

需要添加以下依赖:

    compile 'org.apache.httpcomponents:httpcore:4.4.4'
compile 'org.apache.httpcomponents:httpmime:4.5.1'
compile files('libs/volley.jar')
compile files('libs/activation.jar')

  

使用Volley上传文件的更多相关文章

  1. android Volley 上传文件上传图片

    Volley不解释了吧, android 官方的一个网络请求库. 源码的地址在: git@github.com:com314159/VolleyMultiPartRequest.git 上面的是ssh ...

  2. 使用volley上传多张图片,一个参数对应多张图片,转载

    https://my.oschina.net/u/1177694/blog/491834 原帖地址 而如果使用volley的话,因为请求数据那些都很简便,但遇到上传文件就麻烦那可不好,同时使用多个网络 ...

  3. IE8/9 JQuery.Ajax 上传文件无效

    IE8/9 JQuery.Ajax 上传文件有两个限制: 使用 JQuery.Ajax 无法上传文件(因为无法使用 FormData,FormData 是 HTML5 的一个特性,IE8/9 不支持) ...

  4. 三种上传文件不刷新页面的方法讨论:iframe/FormData/FileReader

    发请求有两种方式,一种是用ajax,另一种是用form提交,默认的form提交如果不做处理的话,会使页面重定向.以一个简单的demo做说明: html如下所示,请求的路径action为"up ...

  5. asp.net mvc 上传文件

    转至:http://www.cnblogs.com/fonour/p/ajaxFileUpload.html 0.下载 http://files.cnblogs.com/files/fonour/aj ...

  6. app端上传文件至服务器后台,web端上传文件存储到服务器

    1.android前端发送服务器请求 在spring-mvc.xml 将过滤屏蔽(如果不屏蔽 ,文件流为空) <!-- <bean id="multipartResolver&q ...

  7. .net FTP上传文件

    FTP上传文件代码实现: private void UploadFileByWebClient() { WebClient webClient = new WebClient(); webClient ...

  8. 通过cmd完成FTP上传文件操作

    一直使用 FileZilla 这个工具进行相关的 FTP 操作,而在某一次版本升级之后,发现不太好用了,连接老是掉,再后来完全连接不上去. 改用了一段时间的 Web 版的 FTP 工具,后来那个页面也 ...

  9. 前端之web上传文件的方式

    前端之web上传文件的方式 本节内容 web上传文件方式介绍 form上传文件 原生js实现ajax上传文件 jquery实现ajax上传文件 form+iframe构造请求上传文件 1. web上传 ...

随机推荐

  1. python-最好大学排名

    # -*- coding: utf-8 -*-"""Created on Mon Apr 3 09:37:52 2017 @author: zuihaodaxuepaim ...

  2. ssh 免密码登录,以及 本地和远端用户名不一致 问题

    ssh 远程登录 ssh -l u1 u1@192.168.0.7 ssh u1@192.168.0.7 每次远程都要输入 用户名,密码 比较麻烦.所以比较好的是免密码登录 1.安装ssh服务器 su ...

  3. 关于EL表达式取值的问题

    EL表达式取值时,如果没有指定作用域,EL表达式会自动按照作用域的大小,从小到大依次去找;比如${s},会自动按照"pageContext,request,session,applicati ...

  4. Ansible 书写我的playbook

    mysql 创建数据库 - hosts: localhost  remote_user: root  tasks: - name: test mysql    mysql_db:      name: ...

  5. java的反射应用

    class B{ public static void main(String[] arg){ Class c_a = Class.forName(packageName + "." ...

  6. sql:查询课程号'0312091006'成绩排名第5到第10之间的学生学号

    select top 6 sno from (select top 10 sno,mark from student_Coursewhere ccno='0312091006' order by ma ...

  7. MySql初步II

    [MySql初步II] 1.Order By 你可以使用 ASC 或 DESC 关键字来设置查询结果是按升序或降序排列. 默认情况下,它是按升排列. 实例: 2.Join语法 Join不是一个关键字 ...

  8. sharepoint 调查问卷权限设置

    参考网址:http://www.cnblogs.com/mybi/archive/2011/04/18/2019935.html 按文章设置后发现访问时提示没有权限. 于是把新权限(问卷回复)的权限组 ...

  9. 基于MSAA的QQ界面信息获取的实现

    主要技术(Microsoft Active Accessibility)讲解: 以下是微软对于此技术的说明 Microsoft Active Accessibility Version 2.0 Pur ...

  10. php下的原生ajax请求

    浏览器中为我们提供了一个JS对象XMLHttpRequet,它可以帮助我们发送HTTP请求,并接受服务端的响应. 意味着我们的浏览器不提交,通过JS就可以请求服务器.   ajax(Asynchron ...