使用浏览器上传文件,然后通过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. 行矩阵列矩阵D3D&GL&U3D

    void Start () { //矩阵函数原型:Matrix4x4(Vector4 colum0, Vector4 colum1, Vector4 colum2, Vector4 colum3),这 ...

  2. 数据类型-Series

    数据类型-Series Series数据类型由一组数据和数据相关的索引组成,键 -> 值 Series数据类型可视为:一维 带标签 数组 Series基本操作类似数组和字典 Series数据类型 ...

  3. ndarray

    ndarray ndarray-多维数组对象 ndarray数组分两部分 实际数据 描述数据的元数据(数据类型/维度等) ndarray所有元素类型相同,下标从0开始 import numpy as ...

  4. Java8Stream

    判断一个操作是惰性求值还是及早求值很简单:只需看它的返回值.如果返回值是 Stream,那么是惰性求值.其实可以这么理解,如果调用惰性求值方法,Stream 只是记录下了这个惰性求值方法的过程,并没有 ...

  5. smartos介绍

    https://wiki.smartos.org A Little History 2005年,Sun Microsystems开源了其著名的Unix操作系统Solaris,最终被发布为一个名为Ope ...

  6. 各种id生成策略

    package com.taotao.utils; import java.util.Random; /** * 各种id生成策略 */ public class IDUtils { /** * 图片 ...

  7. hdoj1010 奇偶剪枝+DFS

    Tempter of the Bone Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Othe ...

  8. CloseableHttpClient(二)

    package com.cmy.httpClient; import java.io.IOException; import org.apache.http.HttpEntity; import or ...

  9. C#操作Excel 单元格的格式处理[xyytIT]

    一. C# 操作 Excel 单元格自动填充,居中对齐,字体颜色等格式设置: Excel.Range titleRange = worksheet.get_Range(worksheet.Cells[ ...

  10. rapidjson使用

    Value构造 Value对象最好先声明后初始化,如果声明直接初始化可能出错. rapidjson::Value a; a = val[i]; Value传参 Value传参,最好显式使用右值,如st ...