使用浏览器上传文件,然后通过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. LVS原理以及配置

    安装好ipvsadm后需要查看内核是否加载了ip_vs模块儿,如果没有需要手动执行ipvsadm进行加载: # ipvsadm # lsmod |grep ip_vs # rmmod ip_vs_rr ...

  2. How To Pronounce 3-Syllable Phrases

    How To Pronounce 3-Syllable Phrases Share Tweet Share Tagged With: 3-Syllable Learn about the stress ...

  3. Rxjs 修改Observable 里的值

    有这么一个对象c$: Observable<any> 修改里边的值: 声明一个subject subject: Subject<any>; 在ngOnInit()中进行初始化 ...

  4. Ubuntu 安装 Elasticsearch

    1.安装java 注意:最新版本的elasticsearch(5.6.2)要求安装java8 1.sudo apt-add-repository ppa:webupd8team/java 2.sudo ...

  5. 大型运输行业实战_day06_1_购票功能简单实现

    1.添加购票按钮 对应的html代码 因为列表是js函数动态填充的,故添加按钮应该在js函数中,完整代码如下: /** * 注意在调用该函数时必须输入参数 * 查询+ 分页 * */ function ...

  6. AnimatorOverrideController

    [AnimatorOverrideController] 有N个角色,这N个角色的状态机一样,只是动画不一样.这时候,新建一个AnimatorController,设置状态机.然后为这N个角色建立N个 ...

  7. MySql的基本架构续

    [数据拆分后引入的问题] 数据水平拆分引入的问题主要是只能通过sharding key来读写操作,例如以userid为sharding key的切分例子,读userid的详细信息时,一定需要先知道us ...

  8. php71 gdnz

    更新yum库:yum updat yum install epel-release yum install -y gcc gcc-c++ autoconf libjpeg libjpeg-devel ...

  9. 数字与字符串之间的转换以及%f与%lf的输入输出用法区别

    1.C++字符串与C字符串的转换: (1)string --> char * string str("OK"); strcpy(p,str.c_str());//p是char ...

  10. Python iter() 函数

    Python iter() 函数  Python 内置函数 描述 iter() 函数用来生成迭代器. 语法 以下是 iter() 方法的语法: iter(object[, sentinel]) 参数 ...