fun getTimeOutInterceptor(): Interceptor {
return Interceptor {
val request: Request = it.request()
val response = it.proceed(request)
try {
val content: String? = response.body()?.string()
response.newBuilder().body(ResponseBody.create(response.body()?.contentType(), content)).build()
} catch (exception: IOException) {
// Toast.makeText( BaseActivity.baseContext , "Time Out :)" , Toast.LENGTH_LONG).show()
Log.d("RetrofitClientInstance", "TimeOutFRomout")
}
response
}
}
1 .I do not understand the following
proceed(request) -> does not call HTTP server ,and send request
response.newBuilder().body(ResponseBody.create(response.body()?.contentType(), content)).build() -> why he rebuild
2 does multiple proceed(request) make it slow
3 how this will handle timeout
Related
We have both asynchronous and synchronous calls implemented using retrofit and Either to map success/error. After adding the network interceptor asynchronous calls are returning bad responses(works fine on postman). I have tried adding a general error JSON response thinking Either is not able to catch the exceptions but still no luck. please suggest a fix or new approach
Interceptorclass -
override fun intercept(chain: Interceptor.Chain): Response {
val request = chain.request()
try {
val response = chain.proceed(request)
val bodyString = response.body!!.string()
return response.newBuilder()
.body(ResponseBody.create(response.body?.contentType(), bodyString))
.build()
} catch (e: Exception) {
e.printStackTrace()
var msg = ""
when (e) {
is SocketTimeoutException -> {
msg = "Timeout - Please check your internet connection"
}
is UnknownHostException -> {
msg = "Unable to make a connection. Please check your internet"
}
is ConnectionShutdownException -> {
msg = "Connection shutdown. Please check your internet"
}
is IOException -> {
msg = "Server is unreachable, please try again later."
}
is IllegalStateException -> {
msg = "${e.message}"
}
else -> {
msg = "${e.message}"
}
}
return Response.Builder()
.request(request)
.protocol(Protocol.HTTP_1_1)
.code(999)
.message(msg)
.body(ResponseBody.create(null, "{${e}}")).build()
}
}`
client - val client1 = OkHttpClient.Builder() .addInterceptor(Interceptor) .build()
ServiceConfig.kt - Adding client as below
#Singleton
#Provides
#BaseUrl(BaseUrlType.SERVICES)
fun provideSupportRetrofit(
jsonConverters: Converter.Factory,
#HttpClient(ClientType.OAUTH) client: Call.Factory
): ServicesFactory {
return fakeServicesFactory ?: Retrofit.Builder()
.callFactory(client)
.baseUrl(baseUrlServices)
.addCallAdapterFactory(EitherCallAdapterFactory())
.addConverterFactory(EitherConverterFactory())
.addConverterFactory(FiberErrorConverterFactory())
.addConverterFactory(jsonConverters)
.addConverterFactory(primitiveTypeConverters)
.client(client1)
.build()
.asFactory
}
EitherCovertor.kt -
`override fun enqueue(callback: Callback<Either<*, *>>) {
call.enqueue(object : Callback<Either<*, *>> {
override fun onResponse(call: Call<Either<*, *>>, response: Response<Either<*, *>>) {
callback.onResponse(this#EitherCall, response.asEither)
}
}
override fun onFailure(call: Call<Either<*, *>>, t: Throwable) {
when (t) {
is Error -> {
Timber.e("Failure Error from API")
callback.onFailure(call, t)
}
else -> callback.onResponse(this#EitherCall, t.asEither)
}
}
})
}`
To get the error text in the header section
headers["Accept"] = "application/json"
and process the error in json form, this way worked for me
Response.ErrorListener { error: VolleyError? ->
if (error is TimeoutError || error is NoConnectionError) {
Constants.checkInternet(context)
} else if (error is ServerError) {
val responseBody = String(error.networkResponse.data, Charsets.UTF_8)
val errorMsg: String =
JSONObject(responseBody).getJSONObject(TAG_META).getJSONObject(
TAG_STATUS)
.getString(TAG_MESSAGE)
Toast.makeText(context, errorMsg + "", Toast.LENGTH_SHORT)
.show()
Log.e("responseBody", responseBody)
Log.e("errorMsg", errorMsg)
}
Loading.hide(loading)
}
I am working in an application : Java Backend and Angular frontend. I am using angular Fromly, data is coming to service, but from the service it is not going to server.
lets share the code snipts:
Service Code:
export class RecommendationRequestService {
readonly ROOT_URL = environment.apiUrl + '/am/v1/recommendation-requests';
constructor(private http: HttpClient, private configService: RecommenderConfigService) {
}
updateData(interviewStatus: InterviewStatusRecommendation): Observable<any> {
console.log(interviewStatus);
return this.http.put<any>(this.ROOT_URL, interviewStatus);
}
}
This line is printing intended data set : console.log(interviewStatus);
The server is running.
The code from where the service is being called :
onSubmit() {
this.model.recommendationRequest.agentInitiationId = this.agentInitiationId;
const subs = this.service.updateData(this.model).subscribe(response => {
console.log('------' + response);
if (response === 'OK') {
this.notify.success('Request Recommendation Update success.');
} else {
this.notify.error('Request Recommendation Update fail.');
}
},
err => {
if (err.error.hasOwnProperty('code') && err.error.code === 1000) {
this.notify.error(CommonEnum.VALIDATION_ERROR);
}
});
subs.unsubscribe();
}
console.log('------' + response); this line should print at least -----, But nothing.
I have checked the network monitor from the browser, no call is going.
What might be the possible issue, any thing from fromly?
You are doing it incorrect as Aldin Bradaric also updated in the comment, as soon as you make the call on the very next moment you are unsubscribing it. This is what you should do :
public subs: [] = [];
onSubmit() {
this.model.recommendationRequest.agentInitiationId = this.agentInitiationId;
const subs = this.service.updateData(this.model).subscribe(response => {
console.log('------' + response);
if (response === 'OK') {
this.notify.success('Request Recommendation Update success.');
} else {
this.notify.error('Request Recommendation Update fail.');
}
},
err => {
if (err.error.hasOwnProperty('code') && err.error.code === 1000) {
this.notify.error(CommonEnum.VALIDATION_ERROR);
}
});
//subs.unsubscribe(); // remove it and add it to the lifecycle hooks
this.subs.push(subs);
}
ngOnDestroy() {
// create an array of subscription
this.subs.forEach(sub => sub.unsubscribe() )
}
I want to integrate google photos api in android,I have done google sign in process but I am not able to get access token because i was getting error in FixedCredentialsProvider.create method while passing parameter.
PhotosLibrarySettings settings =
PhotosLibrarySettings.newBuilder()
.setCredentialsProvider(
FixedCredentialsProvider.create(/ Add credentials here. /))
.build();
try (PhotosLibraryClient photosLibraryClient =
PhotosLibraryClient.initialize(settings)) {
// Create a new Album with at title
Album createdAlbum = photosLibraryClient.createAlbum("My Album");
// Get some properties from the album, such as its ID and product URL
String id = album.getId();
String url = album.getProductUrl();
} catch (ApiException e) {
// Error during album creation
}
I was able to get a solutions to the issue
UserCredentials.newBuilder()
.setClientId("your client id")
.setClientSecret("your client secret")
.setAccessToken("Access Token")
.build()
You can pass this UserCredentials Object to ` FixedCredentialsProvider.create())
Get access token using
val client = OkHttpClient()
val requestBody = FormEncodingBuilder()
.add("grant_type", "authorization_code")
.add("client_id", "")
.add("client_secret", "")
.add("redirect_uri", "")
.add("code", "yourweb server id)
.build()
val request = Request.Builder()
.url("https://www.googleapis.com/oauth2/v4/token")
.post(requestBody)
.build()
client.newCall(request).enqueue(object : Callback {
override fun onFailure(request: Request, e: IOException) {
}
#Throws(IOException::class)
override fun onResponse(response: Response) {
try {
val jsonObject = JSONObject(response.body().string())
mTokenExpired = SystemClock.elapsedRealtime() + jsonObject.optLong("expires_in") * 1000
accessTokenObservable.postValue(Resource.success("",jsonObject.optString("access_token")))
} catch (e: JSONException) {
e.printStackTrace()
}
}
})
https://github.com/erickogi/AndroidGooglePhotosApi
Hope it helps
I'm using Firebase Cloud Functions library on Android, and using getHttpsCallable to call a cloud function.
The problem is that the function needs 10-15 seconds to return the result back to the client, so the client throws an exception java.net.SocketTimeoutException: timeout.
Code
// Create the arguments to the callable function.
Map<String, Object> data = new HashMap<>();
data.put("info", info);
mFunctions.getHttpsCallable(function)
.call(data)
.continueWith(new Continuation<HttpsCallableResult, String>() {
#Override
public String then(#NonNull Task<HttpsCallableResult> task) {
// This continuation runs on either success or failure, but if the task
// has failed then getResult() will throw an Exception which will be
// propagated down.
if (task.isSuccessful()) {
String result = (String) task.getResult().getData();
Log.v(Constants.LOG_TAG, result);
return result;
} else {
// The condition never was true, always logs the exception.
Exception e = task.getException();
Log.e(Constants.LOG_TAG, "Failed to join multiplayer room.", e);
return null;
}
}
});
How can I change the timeout so the client would wait more before throwing the exception?
Note. I'm not using OkHttp, Retrofit or the default system Networking functions, I'm using Firebase Cloud Functions library (getHttpsCallable) to call the function.
firebase-functions version 16.3.0, released 15 Mar 2019, adds the ability to configure the timeout.
I had same issue, so I called https functions with OkHttp instead of getHttpsCallable as a workaround.
The protocol of https.onCall is public.
https://firebase.google.com/docs/functions/callable
The code of calling https functions with OkHttp is here.
https://github.com/ryuta46/firebase-callable-okhttp/blob/56adc5e29a35bdb3b355c14d734e6145da4b6809/android/app/src/main/java/com/ttechsoft/okhttp_callable/MainActivity.kt#L184-L239
Editied.
The code of essential part is below.
private fun callWithOkHttp(functionName: String) {
val idToken = idToken ?: return
val instanceId = instanceId ?: return
val projectId = FirebaseApp.getInstance()?.options?.projectId ?: return
val url = "https://us-central1-$projectId.cloudfunctions.net/$functionName"
val jsonData = JSONObject()
jsonData.put("text", "inputText")
val json = JSONObject()
json.put("data", jsonData)
val requestBody = RequestBody.create(JSON, json.toString())
val request = Request.Builder()
.url(url)
.post(requestBody)
.addHeader("Authorization", "Bearer $idToken")
.addHeader("Firebase-Instance-ID-Token", instanceId)
.build()
val okHttpClient = OkHttpClient.Builder()
.connectTimeout(1 , TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.writeTimeout(1, TimeUnit.MINUTES)
.build()
Log.i(TAG, "Start Okhttp")
okHttpClient.newCall(request).enqueue(object : Callback {
override fun onResponse(call: Call, response: Response) {
if (!response.isSuccessful) {
val message = response.body()?.string() ?: "Network Error"
runOnUiThread {
textOkHttpResult.text = message
}
return
}
runOnUiThread {
textOkHttpResult.text = "OK"
}
val responseBody = response.body()
Log.i(TAG, responseBody?.string())
}
override fun onFailure(call: Call, e: IOException) {
val message = e.message ?: "Unknown Network error"
runOnUiThread {
textOkHttpResult.text = message
}
}
})
}
When registering in the application user gets 2 tokens. Access (lives 1 day) and Refresh (lives 6 months). At a certain point, the Access token will come-one day there will be a custom error. At this , we need to call the refreshToken method and the updated , with which the work will go on.
We call the method, for example getdata , checking for errors, if custom error refreshToken we keep both tokens getdata already with the updated token.
i try but how to rerty call method getdata after refresh token?
mAllApi.getData(new Request().getRequestData())
.flatMap(response -> {
if (response.getError().equals(ECode.ERROR_TOKEN.getCode())) {
mAllApi.getRefreshToken(new String()).flatMap(new Function<AccessToken, ObservableSource<AccessToken>>() {
#Override
public ObservableSource<AccessToken> apply(AccessToken accessToken) throws Exception {
AccessTokenManager.saveNewAccessToken(accessToken);
return null;
}
});
} else {
return Observable.just(response);
}
});
What we did in our app - we created custom OkHttp Interceptor which checks for Access Token each time we do Auth Request and if it's corrupted Interceptor change it with RefreshToken, Add new updated value to Authorization Header and retries Request.
Here is example in Kotlin:
class RefreshAccessTokenInterceptor
#Inject constructor() : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(retryRequest(chain))
return if (response.noAuthError()) {
response
} else {
updateIfNeededOrProcessWithNewToken(chain)
}
}
private fun retryRequest(chain: Interceptor.Chain): Request {
val builder = chain.request().newBuilder()
addAuthHeaders(builder)
return builder.build()
}
private fun Response.noAuthError() = code() != HttpErrorChecker.HTTP_AUTHENTICATION_TIMEOUT
private fun addAuthHeaders(builder: Request.Builder) {
val accessToken = getAccessToken()
if (!accessToken.isNullOrEmpty()) {
builder.header("Authorization", "Bearer $accessToken")
}
}
private fun updateIfNeededOrProcessWithNewToken(chain: Interceptor.Chain): Response {
//here you update your token, add new header and retries request
return chain.proceed(retryRequest(chain))
}
}