The problem is getting buckets on the S3 cloud. The most interesting thing here is that everything works fine on most phones, but not on all models and mainly on Samsung models (there are also Xiaomi and other models). Unfortunately, I'm not very familiar with the service. Is it possible to track requests in the service itself and understand why it gives a 403 error?
Here is the exception I am getting:
Non-fatal Exception: retrofit2.HttpException: HTTP 403 Forbidden
at retrofit2.KotlinExtensions$await$2$2.onResponse(KotlinExtensions.kt:53)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:129)
at okhttp3.RealCall$AsyncCall.run(RealCall.kt:140)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:923)
Here is the method to sign and send keys:
class AwsSignInterceptor(val signer: OkHttpAwsV4Signer) : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request().newBuilder()
.addHeader("host", getHostHeader())
.addHeader("x-amz-date", getXAmzDateheader())
.addHeader("x-amz-content-sha256", "".sha256())
.addHeader("Range", "")
.build()
val signedRequest = signer.sign(request, S3_OBJECT_STORAGE_ACCESS_KEY, S3_OBJECT_STORAGE_SECRET_KEY)
FirebaseCrashlytics.getInstance().log(signedRequest.toString())
return chain.proceed(signedRequest)
}
And here is the method where this exception is thrown:
try {
api.getAlbum("$albumIdInt").downloadToFileWithProgress(albumIdInt)
.collect { download ->
when (download) {
is Download.Progress -> {
notifyWithProgress(download.percent)
}
is Download.Finished -> {
val zip = download.file
val result = mainInteractor.saveAlbum(albumIdInt.toString(), zip)
infoInteractor.update(albumIdInt.toString())
MainScope().launch {
if (result) {
notifyWithFinish()
} else {
notifyWithError()
FirebaseCrashlytics.getInstance().log("Error during saving file")
}
}
}
}
}
} catch (e: Exception) {
MainScope().launch {
Log.e("http", "${e.message}")
notifyWithError()
FirebaseCrashlytics.getInstance().recordException(e)
}
}
Related
I'm using okHttp in Kotlin, but when the server is not running it throws an exception and crashes my app. I want
E/AndroidRuntime: FATAL EXCEPTION: Thread-5
Process: com.mkapps.cvgen, PID: 24497
java.io.IOException: Unexpected code Response{protocol=http/1.1, code=500, message=INTERNAL SERVER ERROR, url=http://192.168.8.103:5000/name}
at com.mkapps.cvgen.fragments.CreateFragment.fetchGithubInfo(CreateFragment.kt:193)
at com.mkapps.cvgen.fragments.CreateFragment.access$fetchGithubInfo(CreateFragment.kt:26)
at com.mkapps.cvgen.fragments.CreateFragment$BackgroundFetcher.run(CreateFragment.kt:217)
at java.lang.Thread.run(Thread.java:784)
val request = Request.Builder().url("http://192.168.8.103:5000/name").post(formBody).build()
val response = client.newCall(request).execute()
if (!response.isSuccessful){
throw IOException("Unexpected code $response")
}else if (response.isSuccessful){
getUrlAsync(NRC)
}
return response.body!!.string()
If you would like to notify the user that they don't have access to the server, you can do so in this way:
inner class BackgroundFetcher : Runnable {
override fun run() { // (3)
try {
val github_info = fetchGithubInfo()
println(github_info)
} catch (e: IOException) {
this#CreateFragment.requireActivity().runOnUiThread {
Toast.makeText(
this#CreateFragment.requireActivity(),
"Make sure you have access to the server",
Toast.LENGTH_SHORT
).show()
}
}
}
}
runOnUiThread is needed because BackgroundFetcher is run on a background thread, and showing a toast is only possible on the UI thread.
I'm trying to make a GET request to my server from my Android application using Retrofit, OKHttp, and Kotlin Flow w/ MVVM architecture.
For some reason whenever I try to invoke my GET request from a try-catch scope the program always enters catch, but the value of Throwable is always null. It's as if there was a crash but no exception being thrown for me to examine in the logs/debugger.
Filtering logcat for OKHTTP logs I can see that the network request never occurs/reaches the server. It seems to be failing locally, somewhere in my device's app process, before triggering the catch block.
Other network calls execute fine in this same project, so something about my specific implementation for this one must be incorrect. What am I missing?
RemoteDataSource.kt
suspend fun getProductData(skuId: String): Result<ProductLookupResponse>{
return getResponse(
request = {
pickingAPI.lookupProductBySku(
"Test User",
"A place",
skuId
)
},
defaultErrorMessage = "Error looking up product"
)
}
private suspend fun <T> getResponse(
request: suspend () -> Response<T>,
defaultErrorMessage: String
): Result<T> {
return try {
val result = request.invoke() //Always Crashes here for this request
if (result.isSuccessful) {
Result.success(result.body())
} else {
val networkError = NetworkError(code = result.code(), message = result.message())
Result.error(message = networkError.message ?: "", error = networkError)
}
} catch (e: Exception) {
Result.error(defaultErrorMessage, null)
}
}
Repo.kt
suspend fun getProductData(
skuId: String
): Flow<Result<ProductLookupResponse>> {
return flow {
emit(Result.loading())
emit(RemoteDataSource.getProductData(skuId))
}.flowOn(Dispatchers.IO)
}
API.kt
#GET("garments/sku/{skuId}")
fun lookupProductBySku(
#Header(HEADER_ASSOCIATE_ID) userUniqueId: String,
#Header(HEADER_LOCATION_ID) dcId: String,
#Path("skuId") sku: String
): Response<ProductLookupResponse>
My Android app crashes and I see this stack trace in Logcat. It doesn't tell me which line of code is causing the problem.
2021-05-05 09:13:33.143 1069-1069/com.mycompany.app E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.mycompany.app, PID: 1069
retrofit2.HttpException: HTTP 403
at retrofit2.KotlinExtensions$await$2$2.onResponse(KotlinExtensions.kt:53)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:161)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Is there a way to map this back to my code, to see which call to retrofit is causing it? I have a repository with code like this:
suspend fun getSomeData(): Stuff {
return withContext(Dispatchers.IO) {
val body = myRetroApi.getStuff()
...
Do I need to wrap every withContext body to make sure no Throwables escape? I thought that if something threw an exception there, it would log an error, not crash the entire app.
Edit
I messed up when asking this question and put the emphasis on wrong things. So I'm removing the "retrofit" tag. It turns out the withContext(Dispatchers.IO) call does re-throw the Exception as expected, but when the exception gets back up to viewModelScope.launch, if that block does not catch it, the app crashes.
If the exception is not handled the app will crash of course.
You can add a try catch to avoid this:
suspend fun getSomeData() {
withContext(Dispatchers.IO) {
try{
val body = myRetroApi.getStuff()
...
} catch (e : Exception){
//your code
}
...
Retrofit is giving you a 403 Unauthorized HTTP exception. It may be that the server isn't passing any additional error message or that you need to catch HttpException and check for the message. In either case, this isn't a Retrofit issue hence it's just passing the error it's getting from the server you're calling.
It's best to create a network result wrapper and a wrapper function for API calls to handle exceptions.
You can do something like this. Keep in mind, the actual implementation is completely up to you. I would however suggest using runCatching when it comes to couroutines as it handles cancellation exceptions.
sealed class NetworkResult<out T> {
data class Success<T>(val data: T) : NetworkResult<T>()
data class Error(val exception: Throwable, val message: String?) : NetworkResult<Nothing>()
}
suspend fun networkCall(): String = ""
suspend fun <T> safeApiCall(block: suspend () -> T): NetworkResult<T> {
return runCatching {
withContext(Dispatchers.IO) {
block()
}
}.fold({
NetworkResult.Success(it)
}, {
when (it) {
is HttpException -> NetworkResult.Error(it, "Network error")
else -> NetworkResult.Error(it, "Some other message...")
// else -> throw it
}
})
}
suspend fun getData() {
val result: NetworkResult<String> = safeApiCall {
networkCall()
}
when (result) {
is NetworkResult.Success -> {
//Handle success
}
is NetworkResult.Error -> { //Handle error
}
}
}
runCatching uses Kotlin's built-in Result class and there are several ways of handling the result. These are just a few.
runCatching {
//.....
}.getOrElse { throwable ->
//handle exception
}
runCatching {
//.....
}.getOrThrow()
runCatching {
}.onSuccess {
}.onFailure {
}
I am trying to do POST request with retrofit and coroutines,
and whenever the HTTP response status is not 200, it just throws an exception. My API has a response body that looks like this:
{
"auth_token": null,
"error": "Email can't be blank. Password can't be blank. First name can't be blank. Last name can't
be blank. Date of birth can't be blank"
}
I want to catch this error message WITHOUT CALLBACKS, is that possible ?
Api service class
#GET("flowers")
suspend fun getAllFlowers(#Query("page") page: Int): Flowers
#POST("users/register")
suspend fun registerUser(#Body user: User) : NetworkResponse
Network response class
class NetworkResponse(
val auth: String,
val error: String)
ViewModel class
fun registerUser(user: User) {
coroutineScope.launch {
try {
val registerUser = FlowerApi.retrofitService.registerUser(user)
_token.value = registerUser.auth
} catch (cause: Throwable) {
//CATCH EXCEPTION
}
}
}
Thanks in advance
Inside your catch block you need to check if the throwable is an HttpException (from Retrofit package) and then you can find the error body from it by calling cause.response()?.errorBody()?.string():
catch (cause: Throwable) {
when (cause) {
is HttpException -> {
cause.response()?.errorBody()?.string() //retruns the error body
}
else -> {
//Other errors like Network ...
}
}
}
AndroidNetworking.upload() is giving bad request in every case.
Testing API on postman which is working fine, but unable to create the same request in AndroidNetworking, any help would be appreciated
Tried AndroidNetworking.post() method which gives a proper response from the server (asking to send file) but in that request unable to add a multipart file, which is required from for server to process.
var request = Rx2AndroidNetworking.upload(ApiEndPoint.SUBMIT_KYC_DOCUMENT)
request.setContentType("multipart/form-data")
request.addMultipartParameter ("json","{\"POADocumentType\":40, \"POIDocumentType\":60,\"ReSubmitDocument\":false}","text/plain")
try {
if (selfie.docFront != null) {
request.addMultipartFile("Selfie", selfie.docFront,"multipart/form-data")
}
} catch (unInitialsied: UninitializedPropertyAccessException) {
}
return request.build()
.setUploadProgressListener(object : UploadProgressListener {
override fun onProgress(bytesUploaded: Long, totalBytes: Long) {
Log.d("", "")
}
})
.getAsJSONObject(object : JSONObjectRequestListener {
override fun onResponse(response: JSONObject?) {
Log.d("", "")
}
override fun onError(anError: ANError?) {
Log.d("", "")
}
})
By the way, it's working in postman
https://ibb.co/3W4qKR6
I dont know how this android networking library works in kotlin but my issue got resolved when I commented
AndroidNetworking.enableLogging();
All my multipart call in this library works fine,after commenting it.