Working POST Multipart Request with Volley and without HttpEntity

前端 未结 5 1334
隐瞒了意图╮
隐瞒了意图╮ 2020-11-22 09:55

This is not really a question, however, I would like to share some of my working code here for your reference when you need.

As we know that HttpEntity

相关标签:
5条回答
  • 2020-11-22 10:12

    Just want to add to the answer. I was trying to figure how to append text fields to the body and created the following function to do it:

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

    It is working pretty well.

    0 讨论(0)
  • 2020-11-22 10:12

    I found a wrapper of the original volley library which is easier to integrate for multi-part requests. It also supports uploading the multi-part data along with other request parameters. Hence I am sharing my code for the future developers who might run into the problem that I was having (i.e. uploading multi-part data using volley along with some other parameters).

    Add the following library in the build.gradle file.

    dependencies {
        compile 'dev.dworks.libs:volleyplus:+'
    }
    

    Please note that, I removed the original volley library from my build.gradle and used the above library instead which can handle both multi-part and normal requests having similar integration technique.

    Then I just had to write the following class which handles the POST request operation.

    public class POSTMediasTask {
        public void uploadMedia(final Context context, String filePath) {
    
            String url = getUrlForPOSTMedia(); // This is a dummy function which returns the POST url for you
            SimpleMultiPartRequest multiPartRequestWithParams = new SimpleMultiPartRequest(Request.Method.POST, url,
                    new Response.Listener<String>() {
                        @Override
                        public void onResponse(String response) {
                            Log.d("Response", response);
                            // TODO: Do something on success
                        }
                    }, new Response.ErrorListener() {
                @Override
                public void onErrorResponse(VolleyError error) {
                    // TODO: Handle your error here
                }
            });
    
            // Add the file here
            multiPartRequestWithParams.addFile("file", filePath);
    
            // Add the params here
            multiPartRequestWithParams.addStringParam("param1", "SomeParamValue1");
            multiPartRequestWithParams.addStringParam("param2", "SomeParamValue2");
    
            RequestQueue queue = Volley.newRequestQueue(context);
            queue.add(multiPartRequestWithParams);
        }
    }
    

    Now execute the task like the following.

    new POSTMediasTask().uploadMedia(context, mediaPath);
    

    You can upload one file at a time using this library. However, I could manage to upload multiple files, just by initiating multiple tasks.

    Hope that helps!

    0 讨论(0)
  • 2020-11-22 10:16

    I rewrite your code @RacZo and @BNK more modular and easy to use like

    VolleyMultipartRequest multipartRequest = new VolleyMultipartRequest(Request.Method.POST, url, new Response.Listener<NetworkResponse>() {
        @Override
        public void onResponse(NetworkResponse response) {
            String resultResponse = new String(response.data);
            // parse success output
        }
    }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {                
            error.printStackTrace();
        }
    }) {
        @Override
        protected Map<String, String> getParams() {
            Map<String, String> params = new HashMap<>();
            params.put("api_token", "gh659gjhvdyudo973823tt9gvjf7i6ric75r76");
            params.put("name", "Angga");
            params.put("location", "Indonesia");
            params.put("about", "UI/UX Designer");
            params.put("contact", "angga@email.com");
            return params;
        }
    
        @Override
        protected Map<String, DataPart> getByteData() {
            Map<String, DataPart> params = new HashMap<>();
            // file name could found file base or direct access from real path
            // for now just get bitmap data from ImageView
            params.put("avatar", new DataPart("file_avatar.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mAvatarImage.getDrawable()), "image/jpeg"));
            params.put("cover", new DataPart("file_cover.jpg", AppHelper.getFileDataFromDrawable(getBaseContext(), mCoverImage.getDrawable()), "image/jpeg"));
    
            return params;
        }
    };
    
    VolleySingleton.getInstance(getBaseContext()).addToRequestQueue(multipartRequest);
    

    Check full of code VolleyMultipartRequest at my gist.

    0 讨论(0)
  • 2020-11-22 10:34

    For those who are struggling to send utf-8 parameters and still no luck, the problem I had was in the dataOutputStream, and change the code of @RacZo to below code:

    private void buildTextPart(DataOutputStream dataOutputStream, String parameterName, String parameterValue) throws IOException {
            dataOutputStream.writeBytes(twoHyphens + boundary + lineEnd);
            dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"");
            dataOutputStream.write(parameterName.getBytes("UTF-8"));
            dataOutputStream.writeBytes(lineEnd);
            dataOutputStream.writeBytes("Content-Type: text/plain; charset=UTF-8" + lineEnd);
            dataOutputStream.writeBytes(lineEnd);
            dataOutputStream.write(parameterValue.getBytes("UTF-8"));
            dataOutputStream.writeBytes(lineEnd);
        } 
    
    0 讨论(0)
  • 2020-11-22 10:37

    Here is a Kotlin version of a class allowing multipart request with Volley 1.1.1.

    It's mostly based on @BNK's solution but slighly simplified. I did not notice any particular performance issue. I uploaded a 5Mb pic in about 3 seconds.

    class MultipartWebservice(context: Context) {
    
        private var queue: RequestQueue? = null
    
        private val boundary = "apiclient-" + System.currentTimeMillis()
        private val mimeType = "multipart/form-data;boundary=$boundary"
    
        init {
            queue = Volley.newRequestQueue(context)
        }
    
        fun sendMultipartRequest(
            method: Int,
            url: String,
            fileData: ByteArray,
            fileName: String,
            listener: Response.Listener<NetworkResponse>,
            errorListener: Response.ErrorListener
        ) {
    
            // Create multi part byte array
            val bos = ByteArrayOutputStream()
            val dos = DataOutputStream(bos)
            buildMultipartContent(dos, fileData, fileName)
            val multipartBody = bos.toByteArray()
    
            // Request header, if needed
            val headers = HashMap<String, String>()
            headers["API-TOKEN"] = "458e126682d577c97d225bbd73a75b5989f65e977b6d8d4b2267537019ad9d20"
    
            val request = MultipartRequest(
                method,
                url,
                errorListener,
                listener,
                headers,
                mimeType,
                multipartBody
            )
    
            queue?.add(request)
    
        }
    
        @Throws(IOException::class)
        private fun buildMultipartContent(dos: DataOutputStream, fileData: ByteArray, fileName: String) {
    
            val twoHyphens = "--"
            val lineEnd = "\r\n"
    
            dos.writeBytes(twoHyphens + boundary + lineEnd)
            dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"$fileName\"$lineEnd")
            dos.writeBytes(lineEnd)
            dos.write(fileData)
            dos.writeBytes(lineEnd)
            dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd)
        }
    
        class MultipartRequest(
            method: Int,
            url: String,
            errorListener: Response.ErrorListener?,
            private var listener: Response.Listener<NetworkResponse>,
            private var headers: MutableMap<String, String>,
            private var mimeType: String,
            private var multipartBody: ByteArray
        ) : Request<NetworkResponse>(method, url, errorListener) {
    
            override fun getHeaders(): MutableMap<String, String> {
                return if (headers.isEmpty()) super.getHeaders() else headers
            }
    
            override fun getBodyContentType(): String {
                return mimeType
            }
    
            override fun getBody(): ByteArray {
                return multipartBody
            }
    
            override fun parseNetworkResponse(response: NetworkResponse?): Response<NetworkResponse> {
                return try {
                    Response.success(response, HttpHeaderParser.parseCacheHeaders(response))
                } catch (e: Exception) {
                    Response.error(ParseError(e))
                }
            }
    
            override fun deliverResponse(response: NetworkResponse?) {
                listener.onResponse(response)
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题