I want to upload image and some data to server. I'm using volley multipart request for that. While uploading the image I'm getting 500 error. I think its related to header part. API works fine in POSTMAN
If I request without boundary value I'm getting 400 error.any solution please provide.thanks in advance
private fun uploadImage() {
OFC_Utils.showProgressDialog(this, "", "")
val token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIwMGE1NzQxNC00M2JmLTQwYTEtODEyMS0zNWIzMTYyMGViZGIiLCJkZXZpY2VJZCI6IjVhNjYyMWQ5LTQwZTgtNGJlMC05MjQ4LWIzY2I2MDkzODdhZSIsImZhcm1JZCI6IiIsImxhbmd1YWdlIjoiRW5nbGlzaCIsInRpbWVab25lIjoiSW5kaWEgU3RhbmRhcmQgVGltZSIsInJvbGUiOiJQQVJBVkVURVJJTkFSSUFOIiwidmVyaWZpY2F0aW9uU3RhdHVzIjoiRmFsc2UiLCJuYmYiOjE2MTE4MTcxNzMsImV4cCI6MTYxMTgxODk3MywiaWF0IjoxNjExODE3MTczfQ.Eo8C6BRyY116JPJmVHEYMPcoZ1Rk2N_mEw4Hj-g4z8M"
val BOUNDARY = "--XX--" //This the boundary which is used by the server to split the post parameters.
val MULTIPART_FORMDATA = "multipart/form-data;boundary=$BOUNDARY"
imageData ?: return
val request = object : VolleyFileUploadRequest(
Method.POST,
Constants.Service_Urls.UPLOAD_FARM_DETAILS,
Response.Listener {
OFC_Utils.hideProgressDialog()
println("response is: $it")
},
Response.ErrorListener { error ->
var response = ""
OFC_Utils.hideProgressDialog()
val networkResponse = error.networkResponse
if (networkResponse != null && networkResponse.data != null) {
// val jsonError = String(networkResponse.data)
// val jsonobject:JSONObject= JSONObject(String(networkResponse.data))
Log.d("jsonerror", String(networkResponse.data))
// response=jsonobject.optString("status")
}
}
) {
override fun getByteData(): Map<String, Any>? {
val params = HashMap<String, FileDataPart>()
val imagename = System.currentTimeMillis()
params["ProfilePicFile"] = FileDataPart(imagename.toString(), imageData!!, "png")
return params
}
override fun getBodyContentType(): String {
return MULTIPART_FORMDATA
}
override fun getBody(): ByteArray {
val params = HashMap<String, String>()
params.put("CountryCode", "+91")
params.put("Phone", "1234567890")
params.put("Role", "PARAVET")
params.put("Name", "NAGS")
params.put("PreferredLanguage", "ENGLISH")
params.put("DeviceName", "REDMI6A")
params.put("DeviceType", "MOBILE")
params.put("Location", "banglore")
Log.d("params1", params.toString())
return params.toString().toByteArray()
}
override fun getHeaders(): MutableMap<String, String> {
val boundary = "apiclient-" + System.currentTimeMillis()
val headers = java.util.HashMap<String, String>()
Log.d("boundary", boundary.toString())
headers["Authorization"] = "bearer $token"
headers["Content-Type"] = MULTIPART_FORMDATA
return headers
}
}
Volley.newRequestQueue(this).add(request)
}
import android.util.Log
import com.android.volley.*
import com.android.volley.toolbox.HttpHeaderParser
import java.io.*
import kotlin.math.min
open class VolleyFileUploadRequest(
method: Int,
url: String,
listener: Response.Listener<NetworkResponse>,
errorListener: Response.ErrorListener) : Request<NetworkResponse>(method, url, errorListener) {
private var responseListener: Response.Listener<NetworkResponse>? = null
init {
this.responseListener = listener
}
private var headers: Map<String, String>? = null
private val divider: String = "--"
private val ending = "\r\n"
//private val boundary = "apiclient-" + System.currentTimeMillis()
private val boundary = "--XX--"
override fun getHeaders(): MutableMap<String, String> =
when(headers) {
null -> super.getHeaders()
else -> headers!!.toMutableMap()
}
override fun getBodyContentType() = "multipart/form-data; boundary=" + boundary
#Throws(AuthFailureError::class)
override fun getBody(): ByteArray {
val byteArrayOutputStream = ByteArrayOutputStream()
val dataOutputStream = DataOutputStream(byteArrayOutputStream)
try {
if (params != null && params.isNotEmpty()) {
Log.d("params",params.toString())
processParams(dataOutputStream, params, paramsEncoding)
}
val data = getByteData() as? Map<String, FileDataPart>?
if (data != null && data.isNotEmpty()) {
processData(dataOutputStream, data)
}
dataOutputStream.writeBytes(divider + boundary + divider + ending)
return byteArrayOutputStream.toByteArray()
} catch (e: IOException) {
e.printStackTrace()
}
return super.getBody()
}
#Throws(AuthFailureError::class)
open fun getByteData(): Map<String, Any>? {
return null
}
override fun parseNetworkResponse(response: NetworkResponse): Response<NetworkResponse> {
return try {
Log.d("del_params",response.toString())
Response.success(response, HttpHeaderParser.parseCacheHeaders(response))
} catch (e: Exception) {
Response.error(ParseError(e))
}
}
override fun deliverResponse(response: NetworkResponse) {
responseListener?.onResponse(response)
Log.d("del_params",response.data.toString())
}
override fun deliverError(error: VolleyError) {
errorListener?.onErrorResponse(error)
// Log.d("error_params",error.message)
}
#Throws(IOException::class)
private fun processParams(dataOutputStream: DataOutputStream, params: Map<String, String>, encoding: String) {
try {
params.forEach {
dataOutputStream.writeBytes(divider + boundary + ending)
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"${it.key}\"$ending")
dataOutputStream.writeBytes(ending)
dataOutputStream.writeBytes(it.value + ending)
}
} catch (e: UnsupportedEncodingException) {
throw RuntimeException("Unsupported encoding not supported: $encoding with error: ${e.message}", e)
}
}
#Throws(IOException::class)
private fun processData(dataOutputStream: DataOutputStream, data: Map<String, FileDataPart>) {
data.forEach {
val dataFile = it.value
dataOutputStream.writeBytes("$divider$boundary$ending")
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"${it.key}\"; filename=\"${dataFile.fileName}\"$ending")
if (dataFile.type != null && dataFile.type.trim().isNotEmpty()) {
dataOutputStream.writeBytes("Content-Type: ${dataFile.type}$ending")
}
dataOutputStream.writeBytes(ending)
val fileInputStream = ByteArrayInputStream(dataFile.data)
var bytesAvailable = fileInputStream.available()
val maxBufferSize = 1024 * 1024
var bufferSize = min(bytesAvailable, maxBufferSize)
val buffer = ByteArray(bufferSize)
var bytesRead = fileInputStream.read(buffer, 0, bufferSize)
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize)
bytesAvailable = fileInputStream.available()
bufferSize = min(bytesAvailable, maxBufferSize)
bytesRead = fileInputStream.read(buffer, 0, bufferSize)
}
dataOutputStream.writeBytes(ending)
}
}
}
class FileDataPart(var fileName: String?, var data: ByteArray, var type: String)
500 means server error. If it works fine on Postman but not on your app it means you are not sending the request properly in your app but you do in Postman. It can be because of the data you're trying to send or any other thing. Try sending the same data you are sending via Postman or using the same headers etc.
But since 500 means server error, you can just ask the backend developer to tell you what is the exact error so you can fix it easily.
Related
I have to send a binary request body in kotlin using volley.
This is the postman call:
enter image description here
I've tried to do it using a solution I found for form-data, but I keep getting 415 response.
Anyone knows how can I do this request using volley?
This is the code I used until now:
open class VolleyFileUploadRequest(
method: Int,
url: String,
listener: Response.Listener,
errorListener: Response.ErrorListener) : Request(method, url, errorListener) {
private var responseListener: Response.Listener? = null
init {
this.responseListener = listener
}
private var headers: Map<String, String>? = null
private val divider: String = "--"
private val ending = "\r\n"
private val boundary = "imageRequest${System.currentTimeMillis()}"
override fun getHeaders(): MutableMap<String, String> =
when(headers) {
null -> super.getHeaders()
else -> headers!!.toMutableMap()
}
override fun getBodyContentType() = "application/form-data;boundary=$boundary"
#Throws(AuthFailureError::class)
override fun getBody(): ByteArray {
val byteArrayOutputStream = ByteArrayOutputStream()
val dataOutputStream = DataOutputStream(byteArrayOutputStream)
try {
if (params != null && params.isNotEmpty()) {
processParams(dataOutputStream, params, paramsEncoding)
}
val data = getByteData() as? Map<String, FileDataPart>?
if (data != null && data.isNotEmpty()) {
processData(dataOutputStream, data)
}
dataOutputStream.writeBytes(divider + boundary + divider + ending)
return byteArrayOutputStream.toByteArray()
} catch (e: IOException) {
e.printStackTrace()
}
return super.getBody()
}
#Throws(AuthFailureError::class)
open fun getByteData(): Map<String, Any>? {
return null
}
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) {
responseListener?.onResponse(response)
}
override fun deliverError(error: VolleyError) {
errorListener?.onErrorResponse(error)
}
#Throws(IOException::class)
private fun processParams(dataOutputStream: DataOutputStream, params: Map<String, String>, encoding: String) {
try {
params.forEach {
dataOutputStream.writeBytes(divider + boundary + ending)
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"${it.key}\"$ending")
dataOutputStream.writeBytes(ending)
dataOutputStream.writeBytes(it.value + ending)
}
} catch (e: UnsupportedEncodingException) {
throw RuntimeException("Unsupported encoding not supported: $encoding with error: ${e.message}", e)
}
}
#Throws(IOException::class)
private fun processData(dataOutputStream: DataOutputStream, data: Map<String, FileDataPart>) {
data.forEach {
val dataFile = it.value
dataOutputStream.writeBytes("$divider$boundary$ending")
dataOutputStream.writeBytes("Content-Disposition: form-data; name=\"${it.key}\"; filename=\"${dataFile.fileName}\"$ending")
if (dataFile.type != null && dataFile.type.trim().isNotEmpty()) {
dataOutputStream.writeBytes("Content-Type: ${dataFile.type}$ending")
}
dataOutputStream.writeBytes(ending)
val fileInputStream = ByteArrayInputStream(dataFile.data)
var bytesAvailable = fileInputStream.available()
val maxBufferSize = 1024 * 1024
var bufferSize = min(bytesAvailable, maxBufferSize)
val buffer = ByteArray(bufferSize)
var bytesRead = fileInputStream.read(buffer, 0, bufferSize)
while (bytesRead > 0) {
dataOutputStream.write(buffer, 0, bufferSize)
bytesAvailable = fileInputStream.available()
bufferSize = min(bytesAvailable, maxBufferSize)
bytesRead = fileInputStream.read(buffer, 0, bufferSize)
}
dataOutputStream.writeBytes(ending)
}
}
}
class FileDataPart(var fileName: String?, var data: ByteArray, var type: String)
And there is the request:
private fun uploadImage(imageData: ByteArray?, idClient: String, idPocket: String, response: Response.Listener, error: Response.ErrorListener) {
imageData?: return
val request = object : VolleyFileUploadRequest(
Method.POST,
"${Endpoints.API_ABT_HOST}${Endpoints.VALIDATE_SELFIE}?idClient=" + idClient + "&dPocket=" + idPocket,
response,
error,
) {
override fun getByteData(): MutableMap<String, FileDataPart> {
var params = HashMap<String, FileDataPart>()
params["imageFile"] = FileDataPart("image", imageData!!, "jpeg")
return params
}
I'm working on a simple app where I add elements in a ListView dynamically, for this I'm using Volley to read JSON and then add all the information inside a data class, as I saw in other questions Volley is asynchronous so when I try to get the size of my list it return 0 because it was executed before Volley.
I can't figure out how to wait for volley to finish before continuing with the code in Kotlin, this is the code where I get the data:
private fun getUsers() {
val url = ""
val requestQueue = Volley.newRequestQueue(this)
val request = JsonObjectRequest(Request.Method.GET, url, null, {
response ->try {
val jsonArray = response.getJSONArray("" + "data")
for (i in 0 until jsonArray.length()) {
val distr = jsonArray.getJSONObject(i)
val getUser = distr.getString("Utilizador").toString()
val getCargo = distr.getString("Cargo").toString()
val getEstado = distr.getString("Estado").toString().toInt()
listUtilizadores.add(Utilizadores(getUser, getCargo, getEstado))
}
} catch (e: JSONException) {
e.printStackTrace()
}
}, { error -> error.printStackTrace() })
requestQueue.add(request)
}
And how I call it inside onCreate()
getUsers()
Log.i("Testing", "Value: " + listUtilizadores.size)
Thank you
Can you try with JsonArrayRequest.
val request =JsonArrayRequest(
url,
Response.Listener { response ->
if (response != null) {
for (i in 0 until response.length()) {
try {
val distr = response.getJSONObject(i)
val getUser = distr.getString("Utilizador").toString()
val getCargo = distr.getString("Cargo").toString()
val getEstado = distr.getString("Estado").toString().toInt()
listUtilizadores.add(Utilizadores(getUser, getCargo, getEstado))
}
} catch (e: JSONException) {
e.printStackTrace()
}
}, { error -> error.printStackTrace() })
requestQueue.add(request)
}
I need make request with Volley and kotlin my cod is
val stringReq = StringRequest(
Request.Method.GET, url,
Response.Listener<String> { response ->
var strResp = response.toString()
val jsonObj: JSONObject = JSONObject(strResp)
val jsonArray: JSONArray = jsonObj.getJSONArray("curso")
for (i in 0 until jsonArray.length()) {
var jsonInner: JSONObject = jsonArray.getJSONObject(i)
listGeral.add(jsonInner.get("interpret").toString());
listGeral2.add(jsonInner.get("titel").toString());
listGeral3.add(jsonInner.get("id").toString());
}
},
Response.ErrorListener {
})
queue.add(stringReq)
Now I need send 3 parameters for php. How do I put instruction for send parameter?
you can write the below code after Response.ErrorListener
val sr: StringRequest = object : StringRequest(Method.POST, "url",
Response.Listener { response ->
//your response
},
Response.ErrorListener { error ->
//your error
}) {
override fun getParams(): Map<String, String> {
val params: MutableMap<String, String> = HashMap()
params["user"] = "YOUR USERNAME"
params["pass"] = "YOUR PASSWORD"
return params
}
#Throws(AuthFailureError::class)
override fun getHeaders(): Map<String, String> {
val params: MutableMap<String, String> = HashMap()
params["Content-Type"] = "application/x-www-form-urlencoded"
return params
}
}
queue.add(sr)
I would like to save response code from volley calls to db, but it seems like parseNetworkResponse() is not being called. Any idea why does it behave like this?
All of my calls are GET, some has code 500 and some has code 200 with json response, so I think it should be called.
private fun createCall(url: String, type: Int, data: JSONObject, callback: Int, request: DbRequestEntity) {
val jsonRequest = object : JsonObjectRequest(type, url, data,
Response.Listener { response ->
Log.d(tag, "Response $response")
try {
callback(response, data, callback, request)
} catch (e: Exception) {
request.responseCode = 999
request.responseMessage = e.message
db.requestMoodel().update(request)
Log.d(tag, "API callback error $e ${e.localizedMessage} ${e.stackTrace}")
}
},
Response.ErrorListener { error ->
Log.d(tag, "API error $error")
errorCallback(error, callback)
}
) {
val tag = "JsonObjectRequest"
override fun getHeaders(): Map<String, String> {
val headers = HashMap<String, String>()
headers[ConstantsStorage.API_HEADER_CLIENT_ID] = ConstantsStorage.API_HEADER_CLIENT_ID_VALUE
headers[ConstantsStorage.API_HEADER_CLIENT_CONTENT_TYPE] = ConstantsStorage.API_HEADER_CLIENT_CONTENT_TYPE_VALUE
return headers
}
override fun parseNetworkResponse(response: NetworkResponse): Response<JSONObject> {
Log.d(tag, "Response code = ${response.statusCode}") //not getting this message to Logcat
return super.parseNetworkResponse(response)
}
}
queue.add(jsonRequest)
}
Replace your parseNetworkResponse function with below code
override fun parseNetworkResponse(response: NetworkResponse): Response<JSONObject> {
try {
if (response.data.length == 0) {
byte[] responseData = "{}".getBytes("UTF8");
response = new NetworkResponse(response.statusCode, responseData, response.headers, response.notModified);
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return super.parseNetworkResponse(response)
}
i have a web service in this url : https://server_IP:9443/api/v1/ssids.json/
but it needs login in this page : https://server_IP:9443/login
when i make the request with the credentials in the headers , i got "Unexpected response code 401"
so how can i authenticate and get the json.
here is my code :
val request = object : StringRequest(Request.Method.GET, url, Response.Listener { response ->
if (response != null) {
Log.e("Your Array Response", response)
} else {
Log.e("Your Array Response", "Data Null")
}
}, Response.ErrorListener { error -> Log.e("error is ", "" + error) }) {
override fun getHeaders() : Map<String, String> {
val username ="admin"
val password = "admin"
val auth = "$username:$password"
var data = auth.toByteArray()
var base64 = Base64.encodeToString(data, Base64.NO_WRAP)
var headers = HashMap<String, String>()
headers.put("Authorization",base64)
headers.put("accept-language","EN")
headers.put("Content-type","application/json")
headers.put("Accept","application/json")
return headers
}
}
val queue = Volley.newRequestQueue(this)
queue.add(request)