How to catch a no network (no internet connection) error from Rxjs Observable using Angular HttpClient
RXJS Catch error code
.catch((err: HttpErrorResponse) => {
if (err.error instanceof Error) {
// A client-side or network error occurred. Handle it accordingly.
console.error('An error occurred:', err.error.message);
} else {
// The backend returned an unsuccessful response code.
// The response body may contain clues as to what went wrong,
console.error(`Backend returned code ${err.status}, body was: ${err.error}`);
}
// ...optionally return a default fallback value so app can continue (pick one)
// which could be a default value
// return Observable.of<any>({my: "default value..."});
// or simply an empty observable
return Observable.empty<T>();
});
Same angular error code
I'm trying to catch errors when the user has no network and is trying to post off an API request. In the code above, it says that err.error instanceof Error would catch any network errors but it doesn't.
Using both Ios and Android simulators, whenever there's no network, I would get a error code of 0 and message, Unknown Error. I can just check when error code 0, then return a no internet connection message but I can never be certain it's actually a network error.
Is there any method to guarantee the error is a no internet connection issue?
Sure I could check for a network before getting or posting api requests, but then all my pages with api requests need to continuously monitor for a network connection.
You could use navigator.onLine as an additional check if you get an error code 0.
Though I'm not sure how reliable this variable is.
Related
So I have these two parallel calls using zip operator. I am making two network calls. I have the following questions:
How can I handle the individual errors correctly
If the first call fails I want to be able to exit the session but if the second network call fails I want to allow the user to still go through the session. I am seeing a 404 in my second network call in the zip and the entire chain fails with an error. I want it to be able to handle success and failure
valid session
response 1: success
response 2: failure
invalid session
response 1: failure
response 2: success
invalid session
both endpoints fail
Single.zip(
api1.getData().doOnError {
// handle error : exit right away
},
api2.getData().doOnError {
// handle error: Set profile data to be empty but when user tries to see the profile information show error at a later point in time based oaths response
// got 404
},
{ response1: String, response2: CustomObject ->
Pair(response1, response2)
}
)
.subscribeOn(Schedulers.io())
.subscribe(
{
handleResponse1(it.first)
handleRespone2(it.second)
},
{
Timber.d("it : $it")
// api1 use success response: is it even possibel to get that in the iterator
// api 2 throwing 404 here
}
)
From your question, I see that you want to continue even if one of the API fails without failing the whole chain. This can be done in the following way
If you want to exit on the first API call no need to handle any Error there.(You will get an error in throwable)
Whenever the second API fails use onErrorReturnItem to return some empty response
Single.zip(
api1.getData().subscribeOn(Schedulers.io()),
api2.getData().subscribeOn(Schedulers.io())
.onErrorReturnItem(new Response())
.......
The new Response() here is just an empty object of the response of type that you were expecting. Even if the second API fails here you will get whatever you are returing
If the first API fails here you will get a callback in Throwable or you can continue to handle error in doOnError
I've created an Android mobile app which has integrated Stripe to accept card payments. In my Android app, I send to my Laravel API, a bunch of parameters, one of which is a Stripe token.
9 times out of 10, my server handles this as expected. It will create a charge object using Stripe-Cartalyst and create a charge, assuming no exceptions are thrown (such as bad card details, or a server error), my api will then proceed to handle the payment as a success and do some inserts into a DB, after which it will return a 201 HTTP status code back to the client, where I then handle this on the Android side.
The bug (or something I'm doing incorrectly) I've encountered though, happens randomly. Occasionally my API will throw an uncaught exception from Stripe explaining a token (encrypted Stripe card details), can only be used once. I've done some debugging on the Android side and can verify I'm only making 1 HTTP request where I send the token, and have done some Logging on my Laravel API, and have found some strange goings on.
What I've found
On the API, I printed some key moments of the process to a log file.
Print the token variable.
When entering the try block to create the charge object.
If 'Delivery' is selected on the Android app (probably a pointless log here).
Checking some items (this is an array passed from the Android app.
At the end of the charge, before returning the 201 back to the client, print a success message of some kind.
I then proceeded to recreate the bug, after about 20/30 orders it happened, and this is the process that occurred:
First, on the Android app, the following token was sent (and printed out to the console);
tok_1DiK0uKIdjSiVG8mn8CV2iim
After checking, this HTTP request was only triggered once, so I don't think it's an Android issue.
Next, on the API log file, the following occurred:
2018-12-17 11:11:56] local.DEBUG: Token: tok_1DiK0uKIdjSiVG8mn8CV2iim
[2018-12-17 11:11:56] local.DEBUG: Creating Stripe Charge
[2018-12-17 11:11:59] local.DEBUG: Token: tok_1DiK0uKIdjSiVG8mn8CV2iim
[2018-12-17 11:11:59] local.DEBUG: Creating Stripe Charge
[2018-12-17 11:12:00] local.ERROR: There is currently another
in-progress request using this Stripe token (that probably means you
clicked twice, and the other charge is still going through):
tok_1DiK0uKIdjSiVG8mn8CV2iim. This token can not be used again if that
charge is successful.' {"exception":"[object]
(Cartalyst\Stripe\Exception\MissingParameterException(code: 400):
There is currently another in-progress request using this Stripe token
(that probably means you clicked twice, and the other charge is still
going through): tok_1DiK0uKIdjSiVG8mn8CV2iim. This token can not be
used again if that charge is successful.' at
/home/rbfs6nkk73qi/api/prototype/vendor/cartalyst/stripe/src/Exception/Handler.php:123)
[stacktrace]
[2018-12-17 11:12:00] local.DEBUG: Delivery order
[2018-12-17 11:12:00] local.DEBUG: Checking single items
[2018-12-17 11:12:00] local.DEBUG: Card delivery - Order placed via
Android V0.5 app
This shows that from the steps I listed 1-5, the API did: 1,2,1,2,error,3,4,5.
I'm at a complete loss as to why my API would randomly run twice. I've pasted the relevant parts of my API below, to see if there is something obviously wrong that I'm doing. Appreciate any help on this.
One last thing I've tried: I've tried setting the $token variable to null directly after creating the $stripe charge object, which makes me wonder if this is some Cartalyst bug.
if($card) {
$token = $request->token; //Stripe token
Log::debug("Token: ".$token); //Step 1
try {
Log::debug("Creating Stripe Charge"); //Step 2
$stripe->charges()->create([
'currency' => $currency,
'amount' => $amount,
'source' => $token
]);
if(strcmp($delivery,"Delivery") == 0) {
Log::debug("Delivery order"); //Step 3
if($singleItems != null) {
Log::debug("Checking single items"); //Step 4
foreach($singleItems as $key => $value) {
$singleItem = DB::table('items')
->select('name','category','price')
->where('item_id', '=', $key)
->get();
foreach($singleItem as $item) {
DB::table('single_order_items')->insert(['order_number' => $id, 'item'=>$key, 'quantity'=>$value, 'name'=>$item->name, 'category'=>$item->category, 'price'=>$item->price]);
}
}
}
Log::debug("Card delivery - ".$description); //Step 5
return response("Order placed successfully", 201)
->header('Content-Type', 'text/plain');
}
} catch(\Cartalyst\Stripe\Exception\BadRequestException $e) {
//This exception will be thrown when the data sent through the request is mal formed.
$message = $e->getMessage();
Log::debug($message);
return response($message, 306)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\UnauthorizedException $e) {
//This exception will be thrown if your Stripe API Key is incorrect.
$message = $e->getMessage();
Log::debug($message);
return response($message, 307)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\InvalidRequestException $e) {
//This exception will be thrown whenever the request fails for some reason.
$message = $e->getMessage();
Log::debug($message);
return response($message, 308)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\NotFoundException $e) {
//This exception will be thrown whenever a request results on a 404.
$message = $e->getMessage();
Log::debug($message);
return response($message, 309)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\CardErrorException $e) {
//This exception will be thrown whenever the credit card is invalid.
$message = $e->getMessage();
Log::debug($message);
return response($message, 310)
->header('Content-Type', 'text/plain');
} catch(\Cartalyst\Stripe\Exception\ServerErrorException $e) {
//This exception will be thrown whenever Stripe does something wrong.
$message = $e->getMessage();
Log::debug($message);
return response($message, 311)
->header('Content-Type', 'text/plain');
}
}
After further debugging, a solution was found. It turns out the HTTP library I'm using on the Android side called Volley was sending the request more than once.
Setting the Volley request to have 0 retries seems to have solved the issue:
MyStringRequest.setRetryPolicy(new DefaultRetryPolicy(0,DefaultRetryPolicy.DEFAULT_MAX_RETRIES,DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
I wan't to achieve next.
Depends on json content deside put or not to put data to Robospice Cache.
Sometimes data returned from the server is not valid. For example our authorization token goes off time. So we shouldn't cache this response.
But i can't find API which can help me to solve this trouble.
Here is how i am using requests now:
getSpiceManager().execute(getRequestCreator().getAllCategories(), getRequestCreator().getLastCacheKey(),
DurationInMillis.ONE_MINUTE * 120, new JSONCategoryListener(mCategories));
So the actual response is normal (status 200), but json content is telling me about exception.
So, what you want to get? It is right behavior for server. Server returns 200, means that request is successful. But it not guarantee, that wasn't some internal error of 'business logic' on server, such as not valid data or anything else.
EDITED
May be you can use your custom error handler:
class MyErrorHandler implements ErrorHandler {
#Override public Throwable handleError(RetrofitError cause) {
//check response on errors
}
}
And in createRestAdapterBuilder():
new RestAdapter.Builder()..setErrorHandler(new MyErrorHandler());
EDITED 2
You can implement in your robospice service method putDataInCache(Object cacheKey, T data), and in your listener check errors in content, and if no error then add it to cache, or remove it from cache
I'm using Titanium SDK 3.4.0 GA, developing an Android app that load remote images from my web server to an ImageView.
The problem comes when the device lost connectivity during the load of that images, so, what I need is a way to catch that error (timeout, 404...) and set an "imageNotAvailable".
I'm using Network Link Conditioner for MacOSX to reproduce that scenario, with low latency, lost of packets...
To prove this I use the following code in my test.js (Alloy Controller) and a simple view with an ImageView with id='imageView' in my test.xml.
Sometimes, throws an exception:
TiDownloadManager: (pool-4-thread-1) [45929,118581] Exception downloading http://...
but not always (remote connection timeout seems infinite), anyway with this exception and without this I can't catch this (probably due to the asynchronous request) nor fires the ERROR event.
function imageNotAvailable(e)
{
Ti.API.info('Error loading image:'+JSON.stringify(e));
$.imageView.image = "/imageNotAvailable.png";
}
function onLoad(e)
{
Ti.API.info('Image Loaded:'+JSON.stringify(e));
}
function setImageAndroid(image)
{
try{
$.imageView.image = 'http://....';
}catch(e){
$.imageView.fireEvent("error");
}
$.imageView.addEventListener("error", imageNotAvailable);
$.imageView.addEventListener("load", onLoad);
}
Excuse my bad English! Thanks!
Have you tried adding your event listeners before setting the imageView's image property?
i can suggest a way around using http request
create a function in some library class which accepts the url that you are supposed to hit
Connection.getImage = function(link){
var xhr = Titanium.Network.createHTTPClient({
onload : function(e) {
var responseResult = this.responseText;
callback(responseResult);
},
// function called when an error occurs, including a timeout
onerror : function(e) {
callback("fail");
// Ti.API.info('IN ERROR ' + e.error);
},
timeout : 5000
});
xhr.open("GET", link);
xhr.send();
};
// ps you will receive a blob in response which you can attach to imageView.blob property , an it would suggest using a default image which will act as placeholder until you get the success response.
I'm making an ajax call that repeatedly calls an api for json data. I've never had it fail with other browsers, but something weird is happening to the response within the Android Browser. I put a console log using weinre that catches the returned data. Can anyone make sense of it and how to handle it?
Screenshot:
Everything is running along smoothly until the last one causes an error like this: Uncaught TypeError: Cannot read property 'Requests' of undefined
Why is it not returning like the previous json return from the ajax calls?
I couldn't find anyway to handle this other than wrap the whole result in a try catch. If it does catch something then it just tries again to get the batch and has thus far always been successful on the second attempt.
try {
//ajax returned result
} catch (error) {
console.error(error);
window.setTimeout(function() {
getBatch();
}, 2000);
}