Android 通过截取发送带有边界的多部分文件时出现问题
我有一个使用标准apache类的客户HTTP调用,但我正在尝试创建一个自定义的Volley类来处理这个问题。以下是标准呼叫的代码:Android 通过截取发送带有边界的多部分文件时出现问题,android,android-volley,multipartform-data,boundary,multipartentity,Android,Android Volley,Multipartform Data,Boundary,Multipartentity,我有一个使用标准apache类的客户HTTP调用,但我正在尝试创建一个自定义的Volley类来处理这个问题。以下是标准呼叫的代码: HttpURLConnection conn = (HttpURLConnection) new URL(strUrl).openConnection(); conn.setDoOutput(true); conn.setDoInput(true); conn.setConnectTimeout(30000); conn.setUseCaches(true); co
HttpURLConnection conn = (HttpURLConnection) new URL(strUrl).openConnection();
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setConnectTimeout(30000);
conn.setUseCaches(true);
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Token " + m_apiKey);
conn.setRequestProperty("Accept", "text/plain , application/json");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + strBoundary);
conn.connect();
// **** Start content wrapper:
DataOutputStream request = new DataOutputStream(conn.getOutputStream());
request.writeBytes("\r\n--" + strBoundary + "\r\n");
request.writeBytes("Content-Disposition: form-data; name=\"" + attachmentName + "\";filename=\"" + imageFileName + "\"" + "\r\n");
request.writeBytes("Content-Type: image/jpeg " + "\r\n");
request.writeBytes("\r\n");
request.write(baos.toByteArray());
// **** End content wrapper:
request.writeBytes("\r\n--"+ strBoundary + "--\r\n");
// Flush output buffer:
request.flush();request.close();
不知道如何做其余的,但这是我的截击没有工作。我以前做过多部分,但没有使用boundary和这种奇怪的格式
公共类ImageMultiRequest扩展了StringRequest{
最终字符串边界=“某物”;
最后一个字符串crlf=“\r\n”;
最后一个字符串双连字符=“--”
private final MultipartEntityBuilder entityBuilder=MultipartEntityBuilder.create();
私有响应。侦听器mListener=null;
private Response.ErrorListener mEListener;
//
私有最终文件mFilePart;
私有映射参数;
私有映射头;
多方实体=新多方实体();
受保护的字符串密钥;
ByteArrayOutputStream bos;
公共ImageMultiRequest(字符串apiKey、字符串url、侦听器rListener、ErrorListener Ellistener、文件){
super(Method.POST、url、rListener、eListener);
setShouldCache(false);
this.apiKey=apiKey;
this.bos=bos;
mListener=rListener;
mEListener=eListener;
mFilePart=文件;
entityBuilder.setMode(与HttpMultipartMode.BROWSER_兼容);
entityBuilder.setBoundary(边界);
buildMultipartEntity();
}
@凌驾
公共字符串getBodyContentType(){
返回“多部分/表单数据;边界=“+boundary+”;字符集=utf-8”;
}
/**
*重写基类以添加Accept:application/json头
*/
@凌驾
公共映射getHeaders()引发AuthFailureError{
Map headers=super.getHeaders();
if(headers==null | | headers.equals(Collections.emptyMap())){
headers=newhashmap();
}
headers.put(“内容类型”、“多部分/表单数据;边界=“+boundary+”;字符集=utf-8”);
标题。放置(“连接”、“保持活动”);
headers.put(“Accept”、“text/plain、application/json”);
headers.put(“授权”、“令牌”+apiKey);
返回标题;
}
@凌驾
公共字节[]getBody()抛出AuthFailureError{
buildMultipartEntity();
ByteArrayOutputStream bos=新建ByteArrayOutputStream();
试一试{
entityBuilder.build().writeTo(bos);
}捕获(IOE异常){
e(“向ByteArrayOutputStream写入IOException”);
}
返回bos.toByteArray();
}
私有void buildMultipartEntity(){
ByteArrayOutputStream bos=新建ByteArrayOutputStream();
addPart(“内容类型:image/jpeg”+crlf+crlf,新的ByteArrayBody(bos.toByteArray(),“car”);
}
}
=================================================
基于以下答案的解决方案
下面是我提出的解决这个问题的方法,可能还有嵌入内容体的多部分文件的其他问题
package com.cars.android.common.volley;
import com.android.volley.AuthFailureError;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.StringRequest;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ImageMultiRequest extends StringRequest {
final String BOUNDARY = "myboundary";
private final MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
HttpEntity entity = new MultipartEntity();
private Response.Listener<String> mListener = null;
private Response.ErrorListener mEListener;
//
private final File mFilePart;
protected String apiKey;
public ImageMultiRequest(String apiKey, String url, Listener<String> rListener, ErrorListener eListener, File file) {
super(Method.POST, url, rListener, eListener);
setShouldCache(false);
this.apiKey = apiKey;
mListener = rListener;
mEListener = eListener;
mFilePart = file;
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
entityBuilder.setBoundary(BOUNDARY);
ContentType contentType = ContentType.create("image/png");
entityBuilder.addBinaryBody("file", file, contentType, "car");
entity = entityBuilder.build();
}
@Override
public String getBodyContentType() {
return entity.getContentType().getValue();
}
/**
* Overrides the base class to add the Accept: application/json header
*/
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = super.getHeaders();
if (headers == null || headers.equals(Collections.emptyMap())) {
headers = new HashMap<String, String>();
}
headers.put("Content-Type", "multipart/form-data;boundary=" + BOUNDARY+ "; charset=utf-8");
headers.put("Connection", "Keep-Alive");
headers.put("Accept", "text/plain , application/json");
headers.put("Authorization", "Token " + apiKey);
return headers;
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
entity.writeTo(bos);
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
return bos.toByteArray();
}
}
package com.cars.android.common.volley;
导入com.android.volley.AuthFailureError;
导入com.android.volley.Response;
导入com.android.volley.Response.ErrorListener;
导入com.android.volley.Response.Listener;
导入com.android.volley.VolleyLog;
导入com.android.volley.toolbox.StringRequest;
导入org.apache.http.HttpEntity;
导入org.apache.http.entity.ContentType;
导入org.apache.http.entity.mime.HttpMultipartMode;
导入org.apache.http.entity.mime.MultipartEntity;
导入org.apache.http.entity.mime.MultipartEntityBuilder;
导入java.io.ByteArrayOutputStream;
导入java.io.File;
导入java.io.IOException;
导入java.util.Collections;
导入java.util.HashMap;
导入java.util.Map;
公共类ImageMultiRequest扩展了StringRequest{
最终字符串边界=“myboundary”;
私有最终MultipartEntityBuilder entityBuilder=MultipartEntityBuilder.create();
HttpEntity=new MultipartEntity();
私有响应。侦听器mListener=null;
private Response.ErrorListener mEListener;
//
私有最终文件mFilePart;
受保护的字符串密钥;
公共ImageMultiRequest(字符串apiKey、字符串url、侦听器rListener、ErrorListener Ellistener、文件){
super(Method.POST、url、rListener、eListener);
setShouldCache(false);
this.apiKey=apiKey;
mListener=rListener;
mEListener=eListener;
mFilePart=文件;
entityBuilder.setMode(与HttpMultipartMode.BROWSER_兼容);
entityBuilder.setBoundary(边界);
ContentType ContentType=ContentType.create(“image/png”);
addBinaryBody(“文件”,file,contentType,“car”);
entity=entityBuilder.build();
}
@凌驾
公共字符串getBodyContentType(){
返回实体.getContentType().getValue();
}
/**
*重写基类以添加Accept:application/json头
*/
@凌驾
公共映射getHeaders()引发AuthFailureError{
Map headers=super.getHeaders();
if(headers==null | | headers.equals(Collections.emptyMap())){
headers=newhashmap();
}
headers.put(“内容类型”、“多部分/表单数据;边界=“+boundary+”;字符集=utf-8”);
标题。放置(“连接”、“保持活动”);
headers.put(“Accept”、“text/plain、application/json”);
headers.put(“授权”、“令牌”+apiKey);
返回标题;
}
@凌驾
公共字节[]getBody()抛出AuthFailureError{
ByteArrayOutputStream bos=新建ByteArrayOutputStream();
试一试{
实体书面形式(bos);
}捕获(IOE异常){
e(“向ByteArrayOutputStream写入IOException”);
}
返回bos.toByteArray();
}
}
这是我的工作示例代码(仅使用小文件进行测试):
公共类FileUploadActivity扩展活动{
私有最终上下文mContext=此;
HttpEntity HttpEntity;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
塞孔特
package com.cars.android.common.volley;
import com.android.volley.AuthFailureError;
import com.android.volley.Response;
import com.android.volley.Response.ErrorListener;
import com.android.volley.Response.Listener;
import com.android.volley.VolleyLog;
import com.android.volley.toolbox.StringRequest;
import org.apache.http.HttpEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class ImageMultiRequest extends StringRequest {
final String BOUNDARY = "myboundary";
private final MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
HttpEntity entity = new MultipartEntity();
private Response.Listener<String> mListener = null;
private Response.ErrorListener mEListener;
//
private final File mFilePart;
protected String apiKey;
public ImageMultiRequest(String apiKey, String url, Listener<String> rListener, ErrorListener eListener, File file) {
super(Method.POST, url, rListener, eListener);
setShouldCache(false);
this.apiKey = apiKey;
mListener = rListener;
mEListener = eListener;
mFilePart = file;
entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
entityBuilder.setBoundary(BOUNDARY);
ContentType contentType = ContentType.create("image/png");
entityBuilder.addBinaryBody("file", file, contentType, "car");
entity = entityBuilder.build();
}
@Override
public String getBodyContentType() {
return entity.getContentType().getValue();
}
/**
* Overrides the base class to add the Accept: application/json header
*/
@Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> headers = super.getHeaders();
if (headers == null || headers.equals(Collections.emptyMap())) {
headers = new HashMap<String, String>();
}
headers.put("Content-Type", "multipart/form-data;boundary=" + BOUNDARY+ "; charset=utf-8");
headers.put("Connection", "Keep-Alive");
headers.put("Accept", "text/plain , application/json");
headers.put("Authorization", "Token " + apiKey);
return headers;
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
entity.writeTo(bos);
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
return bos.toByteArray();
}
}
public class FileUploadActivity extends Activity {
private final Context mContext = this;
HttpEntity httpEntity;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_file_upload);
Drawable drawable = getResources().getDrawable(R.drawable.ic_action_home);
if (drawable != null) {
Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
final byte[] bitmapdata = stream.toByteArray();
String url = "http://10.0.2.2/api/fileupload";
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
// Add binary body
if (bitmapdata != null) {
ContentType contentType = ContentType.create("image/png");
String fileName = "ic_action_home.png";
builder.addBinaryBody("file", bitmapdata, contentType, fileName);
httpEntity = builder.build();
MyRequest myRequest = new MyRequest(Request.Method.POST, url, new Response.Listener<NetworkResponse>() {
@Override
public void onResponse(NetworkResponse response) {
try {
String jsonString = new String(response.data,
HttpHeaderParser.parseCharset(response.headers));
Toast.makeText(mContext, jsonString, Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(mContext, error.toString(), Toast.LENGTH_SHORT).show();
}
}) {
@Override
public String getBodyContentType() {
return httpEntity.getContentType().getValue();
}
@Override
public byte[] getBody() throws AuthFailureError {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
httpEntity.writeTo(bos);
} catch (IOException e) {
VolleyLog.e("IOException writing to ByteArrayOutputStream");
}
return bos.toByteArray();
}
};
MySingleton.getInstance(this).addToRequestQueue(myRequest);
}
}
}
...
}
public class MyRequest extends Request<NetworkResponse>