Как узнать, почему изображение не загружается при использовании Volley?

Я пробовал много способов загрузить изображение на сервер узла, но ни один из них не сработал. Наконец, я наткнулся на библиотеку Ion (https://github.com/koush/ion), чтобы загружать изображения, но это также не работает. Он достигает onCompleteListener, но изображение не загружается в MongoDB. Он отлично работает в Postman, но не в Android. Вот код узла

    const multer= require('multer');
const storage = multer.diskStorage({

  destination: function(req, file, cb) {
    var tok = decode(req.params.id);
    // const url = req.protocol + "://" + req.get("host");
     let path = './images/'+tok.email;
      fs.mkdirsSync(path);
    cb(null, path);
  },
  filename: function(req, file, cb) {
    var tok = decode(req.params.id);
    cb(null, tok.email +'profilePic' + file.originalname);
  }
});
const upload = multer({
  storage: storage,
  limits: {
    fileSize: 1024 * 1024 * 1
  },
  fileFilter: fileFilter
});
app.post('/profilepic/:id',upload.single('profilePic'),function (req,res) {

  // if(!req.session.user){
  //   return res.status(200).send("failure@Not Authorized");
  // }
  var tok = decode(req.params.id);
  console.log(req.file.filename);
  User.updateOne({'_id': tok.id },{'profilePic':tok.email+'/'+req.file.filename}).then(result =>{
      console.log(result);
  if (result.n > 0) {
      res.status(200).json({ message: "success" });
      }else {
        res.status(200).json({ message: "failure@err in Updating pic" });
      }
    })
    .catch(error => {
      res.status(200).json({
        message: "failure@User not found!"
      });
    });

Вот мой код андроида

    private void chooseImage(int imageReq) {
        Intent intent = new Intent();
        intent.setType("image/*");
        intent.setAction(Intent.ACTION_GET_CONTENT);
        startActivityForResult(Intent.createChooser(intent, "Select Picture"), imageReq);
      }



      @Override
      protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PICK_IMAGE_REQUEST)
            && resultCode == RESULT_OK
            && data != null
            && data.getData() != null) {
          showProgressDialog();
          Uri filePath = data.getData();
          Log.d(TAG,getAbsolutePath(filePath));
          uploadFile(getAbsolutePath(filePath));

            Bitmap bitmap = MediaStore.Images.Media.getBitmap(getContentResolver(), filePath);
            Bitmap lastBitmap = null;
            lastBitmap = bitmap;
            if (requestCode == PICK_IMAGE_REQUEST) {


              Glide.with(this)
                  .load(bitmap)
                  .into(profileCoverPic);
}

      }

     public String getAbsolutePath(Uri uri) {
        String[] projection = { MediaStore.MediaColumns.DATA };
        @SuppressWarnings("deprecation")
        Cursor cursor = managedQuery(uri, projection, null, null, null);
        if (cursor != null) {
          int column_index = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
          cursor.moveToFirst();
          return cursor.getString(column_index);
        } else
          return null;
      }

     private void uploadFile(String path){
        Ion.with(getApplicationContext())
            .load(profilePicUrl)
            .setMultipartParameter("name", "source")
            .setMultipartFile("profilepic", "image/jpeg", new File(path))
            .asJsonObject()
            .setCallback(new FutureCallback<JsonObject>() {
              @Override
              public void onCompleted(Exception e, JsonObject result) {
                hideProgressDialog();
                Log.d(TAG,"photo uploaded");
                Toast.makeText(ProfileActivity.this, "Photo uploaded", Toast.LENGTH_SHORT).show();
                //do stuff with result
              }
            });
      }

Любой другой метод также будет оценен.


person Sonu Sourav    schedule 23.07.2019    source источник


Ответы (2)


Для загрузки изображения используйте класс Volleymultipart.

     package com.conceptioni.ashebbicom.util;

    import com.android.volley.AuthFailureError;
    import com.android.volley.NetworkResponse;
    import com.android.volley.ParseError;
    import com.android.volley.Request;
    import com.android.volley.Response;
    import com.android.volley.VolleyError;
    import com.android.volley.toolbox.HttpHeaderParser;

    import java.io.ByteArrayInputStream;
    import java.io.ByteArrayOutputStream;
    import java.io.DataOutputStream;
    import java.io.IOException;
    import java.io.UnsupportedEncodingException;
    import java.util.Map;

 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;


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


protected Map<String, DataPart> getByteData() {
    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);
}


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


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


   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(lineEnd);
    dataOutputStream.writeBytes(parameterValue + lineEnd);
}


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

   public class DataPart {
    private String fileName;
    private byte[] content;
    private String type;

    public DataPart() {
    }

    public DataPart(String name, byte[] data) {
        fileName = name;
        content = data;
    }

    String getFileName() {
        return fileName;
    }

    byte[] getContent() {
        return content;
    }

    String getType() {
        return type;
    }

 }
 }

//////////////////// Используйте этот класс, как показано ниже//////////////////////////

   VolleyMultipartRequest volleyMultipartRequest = new   VolleyMultipartRequest(Request.Method.POST, Constants.edit_photo,
            new Response.Listener<NetworkResponse>() {
                @SuppressLint("ApplySharedPref")
                @Override
                public void onResponse(NetworkResponse response) {
                    try {
                         //Response

                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                    pb.setVisibility(View.GONE);
                }
            },
            new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                }
            }) {


        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            params.put("API", "edit_photo");
           //all params here
            return params;
        }


        @Override
        protected Map<String, DataPart> getByteData() {
            Map<String, DataPart> params = new HashMap<>();
            long imagename = System.currentTimeMillis();
            params.put("var_image", new DataPart(imagename + ".png", getFileDataFromDrawable(bitmap)));
            return params;
        }
    };

    //adding the request to volley
            Volley.newRequestQueue(ActivityProfileDetailSlider.this).add(volleyMultipartRequest);

///////////////////////////////////////////////////////////////

 public byte[] getFileDataFromDrawable(Bitmap bitmap) {
    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.PNG, 80, byteArrayOutputStream);
    return byteArrayOutputStream.toByteArray();
  }
person Mayur Coceptioni    schedule 23.07.2019
comment
Я видел это раньше, но проблема в том, что клиент ожидает ответа сети в случае успеха. Не могли бы вы предоставить мне соответствующий код сервера узла для этого? - person Sonu Sourav; 23.07.2019
comment
String json = new String (response.data, HttpHeaderParser.parseCharset (response.headers)); - person Mayur Coceptioni; 23.07.2019
comment
Нет, я имел в виду, что я могу преобразовать сетевой ответ в String на стороне клиента, но как написать для него код на стороне сервера. Предоставьте полный код сервера узла для составного запроса. - person Sonu Sourav; 23.07.2019

В вашей функции onCompleted() вам нужно проверить, есть ли исключение. Exception даст вам подробную информацию о том, почему он не работает.

public void onCompleted(Exception e, JsonObject result) {
                hideProgressDialog();

                if(e != null){
                  //IN ERROR CASE
                   Log.d(TAG, e.getLocalizedMessage());
                  }else{

                Log.d(TAG,"photo uploaded");
                Toast.makeText(ProfileActivity.this, "Photo uploaded", 
                Toast.LENGTH_SHORT).show();
                //do stuff with result
                 }
              }
            });

Опубликуйте текст исключения в своем сообщении, если вы не понимаете ошибку, которая печатается в LogCat.

person Zohaib Amir    schedule 23.07.2019