通过故障凌空发送分段文件与边界 [英] Trouble Sending Multipart File with Boundary via Volley

查看:177
本文介绍了通过故障凌空发送分段文件与边界的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个客户HTTP调用工作使用标准的Apache类,但我想创建一个自定义的凌空类来处理这个问题。这里是code标准的呼叫:

  HttpURLConnection的康恩=(HttpURLConnection类)新的URL(strUrl).openConnection();
conn.setDoOutput(真正的);
conn.setDoInput(真正的);
conn.setConnectTimeout(30000);
conn.setUseCaches(真正的);
conn.setRequestMethod(POST);
conn.setRequestProperty(授权,令牌+ m_apiKey);
conn.setRequestProperty(接受,text / plain的,应用/ JSON);
conn.setRequestProperty(连接,保持活动);
conn.setRequestProperty(内容类型,多部分/格式数据;边界=+ strBoundary);
conn.connect();


// ****开始内容包装:
DataOutputStream类要求=新DataOutputStream类(conn.getOutputStream());

request.writeBytes(\ r \ N--+ strBoundary +\ r \ N);
request.writeBytes(内容处置:表格数据;名称= \+ attachmentName +\;文件名= \+映像文件名称+\+\ r \ N);
request.writeBytes(内容类型:image / JPEG+\ r \ N);
request.writeBytes(\ r \ N);
request.write(baos.toByteArray());

// ****结束内容包装:
request.writeBytes(\ r \ N  - + strBoundary + -  \ r \ N);

//刷新输出缓冲:
request.flush(); request.close();
 

不知道如何做休息,但是这是我有不工作的抽射高出。我以前而不是已经做了多部与边界和这个奇怪的格式。

公共类ImageMultiRequest扩展StringRequest {     最后弦乐边界=东西;     最后弦乐CRLF =\ r \ N的;     最后弦乐twoHyphens = - ;

 私人最终MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();

私人Response.Listener<字符串> mListener = NULL;
私人Response.ErrorListener mEListener;
//
私人最终文件mFilePart;
私人地图<字符串,字符串>参数;
私人地图<字符串,字符串>头;
MultipartEntity实体=新MultipartEntity();
保护字符串apiKey;
ByteArrayOutputStream BOS;

公共ImageMultiRequest(字符串apiKey,字符串URL,收听LT;字符串> rListener,ErrorListener eListener,档案文件){
    超(Method.POST,网址,rListener,eListener);
    setShouldCache(假);
    this.apiKey = apiKey;
    this.bos = BOS;
    mListener = rListener;
    mEListener = eListener;
    mFilePart =文件;
    entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
    entityBuilder.setBoundary(边界);
    buildMultipartEntity();
}

@覆盖
公共字符串getBodyContentType(){
    返回的multipart / form-data的;边界=+边界+;字符集= UTF-8;
}

/ **
 *覆盖的基类,添加接受:应用/ JSON头
 * /
@覆盖
公共地图<字符串,字符串> getHeaders()抛出AuthFailureError {

    地图<字符串,字符串>标题= super.getHeaders();

    如果(标题== NULL || headers.equals(Collections.emptyMap())){
        标题=新的HashMap<字符串,字符串>();
    }
    headers.put(内容类型,多部分/格式数据;边界=+边界+;字符集= UTF-8);
    headers.put(连接,保持活动);
    headers.put(接受,text / plain的,应用/ JSON);
    headers.put(授权,令牌+ apiKey);
    返回头;
}

@覆盖
公共字节[] getBody()抛出AuthFailureError {
    buildMultipartEntity();

    ByteArrayOutputStream BOS =新ByteArrayOutputStream();

    尝试 {
        。entityBuilder.build()的writeTo(BOS);
    }赶上(IOException异常E){
        VolleyLog.e(IOException异常写入ByteArrayOutputStream);
    }
    返回bos.toByteArray();
}

私人无效buildMultipartEntity(){
    ByteArrayOutputStream BOS =新ByteArrayOutputStream();
    entityBuilder.addPart(内容类型:image / JPEG+ CRLF + CRLF,新ByteArrayBody(bos.toByteArray(),汽车));

  }
}
 

=============================================== ==

解决方案基于以下

答案

下面是我想出了工作,这和其他可能的问题嵌入式多部分文件中的内容主体

 包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实体=新MultipartEntity();

    私人Response.Listener<字符串> mListener = NULL;
    私人Response.ErrorListener mEListener;
    //
    私人最终文件mFilePart;
    保护字符串apiKey;

    公共ImageMultiRequest(字符串apiKey,字符串URL,收听LT;字符串> rListener,ErrorListener eListener,档案文件){
        超(Method.POST,网址,rListener,eListener);
        setShouldCache(假);
        this.apiKey = apiKey;
        mListener = rListener;
        mEListener = eListener;
        mFilePart =文件;
        entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        entityBuilder.setBoundary(边界);

        的ContentType的contentType = ContentType.create(图像/ PNG);
        entityBuilder.addBinaryBody(文件,文件的contentType,汽车);
        实体= entityBuilder.build();
    }

    @覆盖
    公共字符串getBodyContentType(){
        返回entity.getContentType()的getValue()。
    }

    / **
     *覆盖的基类,添加接受:应用/ JSON头
     * /
    @覆盖
    公共地图<字符串,字符串> getHeaders()抛出AuthFailureError {

        地图<字符串,字符串>标题= super.getHeaders();

        如果(标题== NULL || headers.equals(Collections.emptyMap())){
            标题=新的HashMap<字符串,字符串>();
        }
        headers.put(内容类型,多部分/格式数据;边界=+边界+;字符集= UTF-8);
        headers.put(连接,保持活动);
        headers.put(接受,text / plain的,应用/ JSON);
        headers.put(授权,令牌+ apiKey);
        返回头;
    }

    @覆盖
    公共字节[] getBody()抛出AuthFailureError {
        ByteArrayOutputStream BOS =新ByteArrayOutputStream();

        尝试 {
            entity.writeTo(BOS);
        }赶上(IOException异常E){
            VolleyLog.e(IOException异常写入ByteArrayOutputStream);
        }
        返回bos.toByteArray();
    }

}
 

解决方案

这是我的工作示例code(仅适用于小尺寸的文件测试):

 公共类FileUploadActivity延伸活动{

    私人最终上下文mContext =这一点;
    HttpEntity httpEntity;

    @覆盖
    保护无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        的setContentView(R.layout.activity_file_upload);

        可绘制绘制= getResources()getDrawable(R.drawable.ic_action_home)。
        如果(绘制!= NULL){
            点阵位图=((BitmapDrawable)绘制).getBitmap();
            ByteArrayOutputStream流=新ByteArrayOutputStream();
            bitmap.com preSS(Bitmap.Com pressFormat.PNG,100,流);
            最后一个字节[]的BitmapData = stream.toByteArray();
            字符串URL =htt​​p://10.0.2.2/api/fileupload;
            MultipartEntityBuilder建设者= MultipartEntityBuilder.create();
            builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);

            //添加二元体
            如果(的BitmapData!= NULL){
                的ContentType的contentType = ContentType.create(图像/ PNG);
                字符串文件名=ic_action_home.png;
                builder.addBinaryBody(文件的BitmapData,contentType中,文件名);
                httpEntity = builder.build();

                MyRequest myRequest =新MyRequest(Request.Method.POST,网址,新Response.Listener< NetworkResponse>(){
                    @覆盖
                    公共无效onResponse(NetworkResponse响应){
                        尝试 {
                            字符串jsonString =新的String(response.data,
                                    HttpHeaderParser.parseCharset(response.headers));
                            Toast.makeText(mContext,jsonString,Toast.LENGTH_SHORT).show();
                        }赶上(例外五){
                            e.printStackTrace();
                        }
                    }
                },新Response.ErrorListener(){
                    @覆盖
                    公共无效onErrorResponse(VolleyError错误){
                        Toast.makeText(mContext,error.toString(),Toast.LENGTH_SHORT).show();
                    }
                }){
                    @覆盖
                    公共字符串getBodyContentType(){
                        返回httpEntity.getContentType()的getValue()。
                    }

                    @覆盖
                    公共字节[] getBody()抛出AuthFailureError {
                        ByteArrayOutputStream BOS =新ByteArrayOutputStream();
                        尝试 {
                            httpEntity.writeTo(BOS);
                        }赶上(IOException异常E){
                            VolleyLog.e(IOException异常写入ByteArrayOutputStream);
                        }
                        返回bos.toByteArray();
                    }
                };

                MySingleton.getInstance(本).addToRequestQueue(myRequest);
            }
        }
    }

    ...
}

公共类MyRequest扩展请求< NetworkResponse>
 

I have a customers HTTP call working using the standard apache classes but I am trying to create a custom Volley class to handle this. Here is the code for standard call:

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();

Not sure how to do the rest but this is what I have for the Volley that is not working. I've done Multipart before but not with boundary and in this weird format.

public class ImageMultiRequest extends StringRequest { final String BOUNDARY = "something"; final String crlf = "\r\n"; final String twoHyphens = "--";

private final MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();

private Response.Listener<String> mListener = null;
private Response.ErrorListener mEListener;
//
private final File mFilePart;
private Map<String, String> parameters;
private Map<String, String> header;
MultipartEntity entity = new MultipartEntity();
protected String apiKey;
ByteArrayOutputStream bos;

public ImageMultiRequest(String apiKey, String url, Listener<String> rListener, ErrorListener eListener, File file) {
    super(Method.POST, url, rListener, eListener);
    setShouldCache(false);
    this.apiKey = apiKey;
    this.bos = bos;
    mListener = rListener;
    mEListener = eListener;
    mFilePart = file;
    entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
    entityBuilder.setBoundary(BOUNDARY);
    buildMultipartEntity();
}

@Override
public String getBodyContentType() {
    return "multipart/form-data; boundary=" + BOUNDARY + "; charset=utf-8";
}

/**
 * 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 {
    buildMultipartEntity();

    ByteArrayOutputStream bos = new ByteArrayOutputStream();

    try {
        entityBuilder.build().writeTo(bos);
    } catch (IOException e) {
        VolleyLog.e("IOException writing to ByteArrayOutputStream");
    }
    return bos.toByteArray();
}

private void buildMultipartEntity() {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    entityBuilder.addPart("Content-Type: image/jpeg " + crlf + crlf, new ByteArrayBody(bos.toByteArray(), "car"));

  }
}

=================================================

SOLUTION Based on the answer below

Here is what I came up with that worked for this and possibly other problems with multipart file embedded the Content Body

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();
    }

}

解决方案

This is my working sample code (only tested with small-size files):

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>

这篇关于通过故障凌空发送分段文件与边界的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆