2016-11-08 3 views
3

Я пытаюсь опубликовать свое изображение с помощью Volley, но я не могу загрузить свое изображение на сервер. Я всегда получаю com.volley.ServerError. Когда я беру запрос на загрузку изображения с помощью Fiddler, он дает мне код состояния/ошибки 500.Загрузка изображения в виде многостраничного запроса с помощью Volley?

Вот мой код для выбора изображения из галереи:

@Override 
public void onActivityResult(int requestCode, int resultCode, Intent data) { 
    super.onActivityResult(requestCode, resultCode, data); 

    if (data == null) { 
     Toast.makeText(getActivity(), "No Image Selected", Toast.LENGTH_SHORT).show(); 
    } else if (requestCode == Constants.CHOICE_AVATAR_FROM_GALLERY && resultCode == getActivity().RESULT_OK) { 
     Bitmap avatar = getBitmapFromData(data); 


     RestClient restClient = new RestClient(getActivity()); 
    restClient.stringRequest(Constants.PROFILE_IMAGE_UPDATE_REQUEST_ID, Constants.PROFILE_UPDATE_IMAGE_URL, this, imageData); 



     byte[] inputData=null; 
     try { 
      Bundle extra = data.getExtras(); 
      Uri _uri= Uri.parse(extra.get("src_uri").toString()); 
      InputStream iStream = getActivity().getContentResolver().openInputStream(_uri); 
      inputData = getBytes(iStream); 
      size = (inputData.length)/(1024*1024); 

      Log.d("ImageArray", "uri: " + size); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 

     if(size < 3){ 

      imageView.setImageBitmap(avatar); 
      Map<String, String> dataMap = new HashMap<>(); 
      dataMap.put("Email", Utility.sessionEmail(getActivity())); 

      restClient.multiPartImageUploadRequest(Constants.PROFILE_IMAGE_UPDATE_REQUEST_ID, 
        url, this, dataMap, inputData); 

     }else { 
      imageView.setImageResource(R.drawable.ic_camera); 
      Toast.makeText(getActivity(), "Image size shuld not exceed 3 MB", Toast.LENGTH_SHORT).show(); 
     } 

    } 


} 

public String getPath(Uri uri) { 
    Cursor cursor = getActivity().getContentResolver().query(uri, null, null, null, null); 
    cursor.moveToFirst(); 
    String document_id = cursor.getString(0); 
    document_id = document_id.substring(document_id.lastIndexOf(":") + 1); 
    cursor.close(); 



    cursor = getActivity().getContentResolver().query(
      android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, 
      null, MediaStore.Images.Media._ID + " = ? ", new String[]{document_id}, null); 
    cursor.moveToFirst(); 
    String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); 
    cursor.close(); 

    return path; 
} 

public void selectImage(View view) { 

    Intent intent = new Intent(Intent.ACTION_GET_CONTENT); 

    intent.setType("image/*"); 
    intent.setAction(Intent.ACTION_GET_CONTENT); 
    startActivityForResult(getCropIntent(intent), Constants.CHOICE_AVATAR_FROM_GALLERY); 
} 


private Intent getCropIntent(Intent intent) { 

    intent.putExtra("crop", "true"); 
    intent.putExtra("aspectX", 1); 
    intent.putExtra("aspectY", 1); 
    intent.putExtra("outputX", 320); 
    intent.putExtra("outputY", 320); 
    intent.putExtra("return-data", true); 

    return intent; 
} 

public Bitmap getBitmapFromData(Intent data) { 
    Bitmap photo = null; 
    Uri photoUri = data.getData(); 


    if (photoUri != null) { 
     photo = BitmapFactory.decodeFile(photoUri.getPath()); 
     path = getPath(photoUri); 
     uri = photoUri; 
     Log.d("URI", "" + photoUri); 
    } 
    if (photo == null) { 
     Bundle extra = data.getExtras(); 
     if (extra != null) { 
      photo = (Bitmap) extra.get("data"); 
      ByteArrayOutputStream stream = new ByteArrayOutputStream(); 
      photo.compress(Bitmap.CompressFormat.JPEG, 90, stream); 

     } 
    } 
    return photo; 
} 

Это метод для обработки загрузить POST запрос

public void multiPartImageUploadRequest(int id, String url, ResponseHandler handler, Map<String, String> data, byte[] image){ 

    int request_id = id; 
    final ResponseHandler responseHandler = handler; 
    final Map<String, String> params = data; 
    final byte[] imageData = image; 

    pDialog = new ProgressDialog(context); 
    pDialog.setMessage("Uploading Image..."); 
    pDialog.show(); 

    VolleyMultipartRequest request = new VolleyMultipartRequest(Request.Method.POST, url, 
      new Response.Listener<NetworkResponse>() { 
     @Override 
     public void onResponse(NetworkResponse response) { 
      String resultResponse = new String(response.data); 
      responseHandler.success(resultResponse, Constants.PROFILE_IMAGE_UPDATE_REQUEST_ID); 
      pDialog.dismiss(); 

     } 
    }, new Response.ErrorListener() { 
     @Override 
     public void onErrorResponse(VolleyError error) { 
      responseHandler.failure(error, Constants.PROFILE_IMAGE_UPDATE_REQUEST_ID); 
      pDialog.dismiss(); 
      error.printStackTrace(); 
     } 
    }) { 
     @Override 
     protected Map<String, String> getParams() { 
      return params; 
     } 

     @Override 
     protected Map<String, DataPart> getByteData() { 
      Map<String, DataPart> ImageParams = new HashMap<>(); 
      // file name could found file base or direct access from real path 
      // for now just get bitmap data from ImageView 
      ImageParams.put("", new DataPart("file_avatar.jpg", imageData, "image/jpeg")); 

      return ImageParams; 
     } 
    }; 
    request.setRetryPolicy(new DefaultRetryPolicy(30*1000, 1, 1.0f)); 

    RestController.getInstance().addToRequestQueue(request); 



} 

VolleyMultipartRequest.java

public class VolleyMultipartRequest extends Request<NetworkResponse> { 


    private final String twoHyphens = "--"; 
    private final String lineEnd = "\r\n"; 
    private final String boundary = "apiclient-" + System.currentTimeMillis(); 

    private Response.Listener<NetworkResponse> mListener; 
    private Response.ErrorListener mErrorListener; 
    private Map<String, String> mHeaders; 


    /** 
    * Default constructor with predefined header and post method. 
    * 
    * @param url   request destination 
    * @param headers  predefined custom header 
    * @param listener  on success achieved 200 code from request 
    * @param errorListener on error http or library timeout 
    */ 
    public VolleyMultipartRequest(String url, Map<String, String> headers, 
            Response.Listener<NetworkResponse> listener, 
            Response.ErrorListener errorListener) { 
     super(Method.POST, url, errorListener); 
     this.mListener = listener; 
     this.mErrorListener = errorListener; 
     this.mHeaders = headers; 
    } 

    /** 
    * Constructor with option method and default header configuration. 
    * 
    * @param method  method for now accept POST and GET only 
    * @param url   request destination 
    * @param listener  on success event handler 
    * @param errorListener on error event handler 
    */ 
    public VolleyMultipartRequest(int method, String url, 
            Response.Listener<NetworkResponse> listener, 
            Response.ErrorListener errorListener) { 
     super(method, url, errorListener); 
     this.mListener = listener; 
     this.mErrorListener = errorListener; 
    } 

    @Override 
    public Map<String, String> getHeaders() throws AuthFailureError { 
     return (mHeaders != null) ? mHeaders : super.getHeaders(); 
    } 

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

    @Override 
    public byte[] getBody() throws AuthFailureError { 
     ByteArrayOutputStream bos = new ByteArrayOutputStream(); 
     DataOutputStream dos = new DataOutputStream(bos); 

     try { 
      // populate text payload 
      Map<String, String> params = getParams(); 
      if (params != null && params.size() > 0) { 
       textParse(dos, params, getParamsEncoding()); 
      } 

      // populate data byte payload 
      Map<String, DataPart> data = getByteData(); 
      if (data != null && data.size() > 0) { 
       dataParse(dos, data); 
      } 

      // close multipart form data after text and file data 
      dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd); 

      return bos.toByteArray(); 
     } catch (IOException e) { 
      e.printStackTrace(); 
     } 
     return null; 
    } 

    /** 
    * Custom method handle data payload. 
    * 
    * @return Map data part label with data byte 
    * @throws AuthFailureError 
    */ 
    protected Map<String, DataPart> getByteData() throws AuthFailureError { 
     return null; 
    } 

    @Override 
    protected Response<NetworkResponse> parseNetworkResponse(NetworkResponse response) { 
     try { 
      return Response.success(
        response, 
        HttpHeaderParser.parseCacheHeaders(response)); 
     } catch (Exception e) { 
      return Response.error(new ParseError(e)); 
     } 
    } 

    @Override 
    protected void deliverResponse(NetworkResponse response) { 
     mListener.onResponse(response); 
    } 

    @Override 
    public void deliverError(VolleyError error) { 
     mErrorListener.onErrorResponse(error); 
    } 

    /** 
    * Parse string map into data output stream by key and value. 
    * 
    * @param dataOutputStream data output stream handle string parsing 
    * @param params   string inputs collection 
    * @param encoding   encode the inputs, default UTF-8 
    * @throws IOException 
    */ 
    private void textParse(DataOutputStream dataOutputStream, Map<String, String> params, String encoding) throws IOException { 
     try { 
      for (Map.Entry<String, String> entry : params.entrySet()) { 
       buildTextPart(dataOutputStream, entry.getKey(), entry.getValue()); 
      } 
     } catch (UnsupportedEncodingException uee) { 
      throw new RuntimeException("Encoding not supported: " + encoding, uee); 
     } 
    } 

    /** 
    * Parse data into data output stream. 
    * 
    * @param dataOutputStream data output stream handle file attachment 
    * @param data    loop through data 
    * @throws IOException 
    */ 
    private void dataParse(DataOutputStream dataOutputStream, Map<String, DataPart> data) throws IOException { 
     for (Map.Entry<String, DataPart> entry : data.entrySet()) { 
      buildDataPart(dataOutputStream, entry.getValue(), entry.getKey()); 
     } 
    } 

    /** 
    * Write string data into header and data output stream. 
    * 
    * @param dataOutputStream data output stream handle string parsing 
    * @param parameterName name of input 
    * @param parameterValue value of input 
    * @throws IOException 
    */ 
    private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException { 
     dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd); 
     dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + parameterName + "\"" + lineEnd); 
     //dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd); 
     dataOutputStream.writeBytes(lineEnd); 
     dataOutputStream.writeBytes(parameterValue + lineEnd); 
    } 

    /** 
    * Write data file into header and data output stream. 
    * 
    * @param dataOutputStream data output stream handle data parsing 
    * @param dataFile   data byte as DataPart from collection 
    * @param inputName  name of data input 
    * @throws IOException 
    */ 
    private void buildDataPart(DataOutputStream dataOutputStream, DataPart dataFile, String inputName) throws IOException { 
     dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd); 
     dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"" + 
       inputName + "\"; filename=\"" + dataFile.getFileName() + "\"" + lineEnd); 
     if (dataFile.getType() != null && !dataFile.getType().trim().isEmpty()) { 
      dataOutputStream.writeBytes("Content-Type: " + dataFile.getType() + lineEnd); 
      Log.d("Name", inputName + "  " + dataFile.getFileName()); 
     } 
     dataOutputStream.writeBytes(lineEnd); 

     ByteArrayInputStream fileInputStream = new ByteArrayInputStream(dataFile.getContent()); 
     int bytesAvailable = fileInputStream.available(); 

     int maxBufferSize = 1024 * 1024; 
     int bufferSize = Math.min(bytesAvailable, maxBufferSize); 
     byte[] buffer = new byte[bufferSize]; 

     int bytesRead = fileInputStream.read(buffer, 0, bufferSize); 

     while (bytesRead > 0) { 
      dataOutputStream.write(buffer, 0, bufferSize); 
      bytesAvailable = fileInputStream.available(); 
      bufferSize = Math.min(bytesAvailable, maxBufferSize); 
      bytesRead = fileInputStream.read(buffer, 0, bufferSize); 
     } 

     dataOutputStream.writeBytes(lineEnd); 
    } 

    /** 
    * Simple data container use for passing byte file 
    */ 
    public class DataPart { 
     private String fileName; 
     private byte[] content; 
     private String type; 

     /** 
     * Default data part 
     */ 
     public DataPart() { 
     } 

     /** 
     * Constructor with data. 
     * 
     * @param name label of data 
     * @param data byte data 
     */ 
     public DataPart(String name, byte[] data) { 
      fileName = name; 
      content = data; 
     } 

     /** 
     * Constructor with mime data type. 
     * 
     * @param name  label of data 
     * @param data  byte data 
     * @param mimeType mime data like "image/jpeg" 
     */ 
     public DataPart(String name, byte[] data, String mimeType) { 
      fileName = name; 
      content = data; 
      type = mimeType; 
     } 

     /** 
     * Getter file name. 
     * 
     * @return file name 
     */ 
     public String getFileName() { 
      return fileName; 
     } 

     /** 
     * Setter file name. 
     * 
     * @param fileName string file name 
     */ 
     public void setFileName(String fileName) { 
      this.fileName = fileName; 
     } 

     /** 
     * Getter content. 
     * 
     * @return byte file data 
     */ 
     public byte[] getContent() { 
      return content; 
     } 

     /** 
     * Setter content. 
     * 
     * @param content byte file data 
     */ 
     public void setContent(byte[] content) { 
      this.content = content; 
     } 

     /** 
     * Getter mime type. 
     * 
     * @return mime type 
     */ 
     public String getType() { 
      return type; 
     } 

     /** 
     * Setter mime type. 
     * 
     * @param type mime type 
     */ 
     public void setType(String type) { 
      this.type = type; 
     } 
    } 
} 

ответ

1

Итак, понимание того, что именно неправильно, потребует некоторой отладки, я могу поделиться с моим опытом.

отказ от ответственности: я сам перешел к использованию Retrofit2.0 и рекомендовал бы, чтобы кто-то делал то же самое, поскольку он быстрее, проще в использовании и значительно более документирован мой предыдущий опыт работы с Volley

в моем случае мне нужно, чтобы загрузить изображение вместе с текстовым полем, многосекционный класс я построил был немного другой:

Главное, я MultiPartEntityBuilder упрощающий материал, и сам класс расширяет Request<String>, так как это был тип ответа (который легче поддается ле обычно), так что это будет конструктор:

public MultiPartImageRequest(String url, String filePath, Response.Listener<String> listener, Response.ErrorListener errorListener) 
{ 
    super(Method.POST, url, errorListener); 
    this.listener = listener; 
    this.entityBuilder = MultipartEntityBuilder.create(); 
    this.httpEntity = new MultipartEntity(); 
    setShouldCache(false); 
    this.file = new File(filePath); 

    this.entityBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE); 
    this.entityBuilder.setBoundary(generateBoundary()); 

    buildMultipartImageEntity(); 
} 

создал граничном себя, и построила объект с бинарным телом, содержащим файл, и мое текстовым полем, давая соответствующий тип содержимого, например, так:

private void buildMultipartImageEntity() 
{ 
    try 
    { 
     ContentType contentType = ContentType.create("image/jpeg"); 

     entityBuilder.addBinaryBody("userfile", file, contentType, file.getName()); 
     entityBuilder.addTextBody("userid", String.valueOf(SettingsManager.getUserID()), ContentType.TEXT_PLAIN); 
     httpEntity = entityBuilder.build(); 

    } 
    catch (Exception e) 
    { 
     VolleyLog.e("UnsupportedEncodingException"); 
    } 
} 

private static final char[] MULTIPART_CHARS = "-_1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); 

private String generateBoundary() 
{ 
    StringBuilder buffer = new StringBuilder(); 
    Random rand = new Random(); 
    int count = rand.nextInt(11) + 30; 

    for (int i = 0; i < count; ++i) 
    { 
     buffer.append(MULTIPART_CHARS[rand.nextInt(MULTIPART_CHARS.length)]); 
    } 

    return buffer.toString(); 
} 

от там, getBodyContentType и getBody использовать объект httpEntity:

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

и еще одна вещь, я нашел, была необходимость проанализировать реакцию в UTF-8, но не может быть необходимы в вашем случае (в зависимости от ответа):

@Override 
protected Response<String> parseNetworkResponse(NetworkResponse response) 
{ 
    try 
    { 
     String responseBody = new String(response.data, "utf-8"); 
     return (Response.success(responseBody, getCacheEntry())); 
    } 
    catch (UnsupportedEncodingException e) 
    { 
     VolleyLog.e("UnsupportedEncodingException"); 
     return (Response.success("Uploaded, problem with url return", getCacheEntry())); 
    } 
} 

Надеется, что это помогает в любом случае.

Смежные вопросы