Network request in react native fails after two minutes - android

I am having some trouble using couchdb in react native. See code below :
const urlcouchdb = 'http://192.168.58.1:5984';
export const login = async (name, password) => {
const response = await fetch(`${urlcouchdb}/_session`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
name,
password,
}),
}).catch(function(error) {
console.log("error = " + error);
return error;
});
if (
response.headers &&
response.headers.map['set-cookie'] &&
response.headers.map['set-cookie'][0]
) {
await AsyncStorage.setItem(
'cookiecouchdb',
response.headers.map['set-cookie'][0],
);
}
return response.json();
}
At first, I was using my localhost IP (127.0.0.1), and I was getting this error : TypeError: Network request failed.
After some researches, I've figured out I'd better change it to the IP address of system. I thought my problem was solved, because I was not getting the error anymore, but it turned out that I was still getting the same error, but two minutes (approximatly), after doing the request!
It's very annoying to wait two minutes every single time I try to solve it. Do you have any idea why my request fails?
Just to let you know : The name and password I send to login function are correct. Also, I am testing on my android device, using expo.

Related

Fetch DELETE method on Android (React Native)

I make several requests from a React Native app to an API. Every request works fine both on iOS and Android except the DELETE method that does not work on Android. The call is correctly made, it goes through the API and the objects are deleted. But instead of getting the response, the call falls under the catch statement with [TypeError: Network request failed]. This does not happen in iOS.
Some people with the same problem were missing 'Content-Type': 'application/json' on the request headers which is not my case.
This is happening both locally, in testing and production stages (using an ip instead of localhost will do nothing).
The request is also successfully performed in Postman.
What can it be?
React Native 0.63.5
export const deleteApi = async (api: string, body?: any) => {
const userResponse = await getUserCredentials();
const authState = await getAuthState();
let response = await fetch(api, {
method: 'DELETE',
headers: await getHeaders(userResponse, authState),
body: JSON.stringify(body)
});
if (response.status === UNAUTHENTICATED_CODE)
response = await interceptor(response, userResponse, {
api: api,
method: 'DELETE',
body: body
});
return response;
};
leaveClass = async (
uuid: string,
onSuccess: () => void,
onFailure: (error: string) => void,
) => {
this.setLoading(true);
try {
const api = LEAVE_CLASS_API_PREFIX + uuid + LEAVE_CLASS_API_SUFFIX;
const response = await deleteApi(api);
if (response.status === SUCCESS_STATUS_CODE) {
onSuccess();
}
else {
const jsonResponse = await response.json();
if (jsonResponse.detail) onFailure(jsonResponse.detail);
else onFailure(translations.SOMETHING_WENT_WRONG);
}
} catch (error) {
console.log('leaveClass error: ', error);
}
this.setLoading(false);
};
You can use a network plugin for Flipper (https://fbflipper.com/docs/setup/plugins/network/), copy your request from it as a curl, and try to perform it from your terminal or postman. If it has the same error, the problem is not in React Native.

Axios timeout not working as expected on limited hotspot

I am using axios for one of my react native project. Here's my config and executing code:
const config = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
timeout: 30000
};
var response = await instance.get(route, config);
Here is my testing scenario. I have two phones, A and B. From phone A I open my wifi and also create a hotspot. From phone B I connect to that hotspot. Now I turn of wifi on phone A which has hotspot on. For phone B network is available but it shows as limited.
Now if I place an HTTP using above axios configuration, it never times out after 30 seconds for Android devices. But for iOS devices it works as expected. Why?
It happened with me and i solved it manually by doing the following
let source = axios.CancelToken.source();
setTimeout(() => {
source.cancel();
// Timeout Logic
}, 30000);
const config = {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
timeout: 30000,
//Add this
cancelToken: source.token,
};
The problem I ran into with Hassan's solution is that even though the request did get cancelled, I was using the same token to cancel all requests, so afterwards every request was immediately cancelled, without even attempting. This broke my app.
I solved this using a request interceptor:
const myInstance = axios.create(config);
const myTimeoutLimit = 15000;
const guaranteeTimeout = (config) => {
config.cancelToken = new axios.CancelToken((cancelRequest) => {
setTimeout(() => cancelRequest('Optional message'),
myTimeoutLimit);
});
return config;
};
myInstance.interceptors.request.use(guaranteeTimeout);
So you basically create a new token per request, if the request takes more than your defined limit, we cancel that particular request.
Axios documentation

axios post request working in React Native ios but not in android

I know there many answers regarding to this question but I can't seem to find one that works for me. I'm sending a post request to my server using axios but it does not work in android although it does in ios. I'm currently using server ip address (not localhost), and I'm also sending headers when request but it is still not going through the network request for android.
import axios from 'axios';
const SERVER_URL = 'http://serverip:3000';
export function signin({ username, password }) {
return function(dispatch) {
axios.post(`${SERVER_URL}/user/authenticate`, { username, password }, { headers: { 'Content-Type': 'application/json' } })
.then((response) => {
console.log('login response', response);
dispatch({
type: USER_AUTH,
});
AsyncStorage.setItem('token', response.data.token || '');
})
.catch((response) => console.log('user sign in err', response));
};
}
Has anyone had similar issue like myself and know how to make this work?
Thank you,
Set header to
headers: {
Accept: 'application/json',
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
},

Including csrf token in a post request from react-native app

I have a react native app that posts and gets data from a remote server. In post, i need to include csrf token to avoid token mismatch errors. This is the backend laravel method
//Android Login
public function androidLogin(){
return response()->json([
'name' => 'Android Login',
'route' => 'androidLogin'
]);
}
This is the react native code(i have stripped out error catching code).
async handleSubmit(){
var me = this.state.message;
console.log('this connected',me);
let response = await fetch('http://not-brusselus.be/androidLogin', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
'X-CSRF-TOKEN':'csrf_field()'
},
body: JSON.stringify({
session:{
email: 'chesterfield#gmail.com',
password: '123456',
}
})
});
//let res = await response.text();
if (true) {
console.log(response);
} else {
//Handle error
//let error = res;
//throw error;
}
}
The response shows laravel's token mismatch page. How can i send the csrf token successfully?.
Hang the CSRF token off of the window as defined in your main laravel layout file:
window.Laravel = {
csrfToken: '{{csrf_token()}}'
}
Then just use that in your javascript requests:
...window.Laravel.csrfToken
Edit
To the downvoter: This is literally how Laravel does it out of the box and recommends you do it as well.

Angular2 custom request

I am using a custom HTTP request class for adding a Authorization Header to all of my requests, this works fine on almost every android device. Wired thing now is that I got some customer complaints that they are getting the 'No internet connection' error although they have a working network connection (other apps work and the errors are transmitted to the Sentry servers also).
As I am using Sentry error tracking I found out that these customers are all getting the error because the timeout error is thrown after 10 seconds for the first request at app start.
I guessed that something has to be wrong with this request so I built an alpha version for a limited number of users to track down the error (I send the options of every request to Sentry), but the requests look fine.
Next guess was that something is wrong with cordova-plugin-nativestorage on these devices but as I am catching them it should at lease return an empty token. No clue how to fix it right now. Any advice is appreciated!
export class CustomRequest {
apiToken: string = '';
constructor(private http: Http) { }
protected request(options: any): Observable<any> {
// If Native Storage doens't find a token, return an empty
let errorNativeStorage$ = function (): Observable<any> {
return Observable.of({ Token: '' });
};
// Get Token form Native Storage
let token$ = Observable.fromPromise(NativeStorage.getItem('JWT'))
.catch(errorNativeStorage$);
// Handle request errors
let genericError$ = function (error: Response | any): Observable<any> {
let errMsg: string;
if (error instanceof Response) {
const body = error.json() || '';
const err = body.error || JSON.stringify(body);
errMsg = `${error.status} - ${error.statusText || ''} ${err}`;
} else {
errMsg = error.message ? error.message : error.toString();
}
console.error(errMsg);
Raven.captureException(error, { extra: { errorMsg: errMsg } });
return Observable.of({
Errors: { General: 'No internet connection.' }
});
};
// the request
let request$ = (options) => {
return this.http.request(new Request(options))
.retryWhen(error => error.delay(1000))
.timeout(10000, new Error('timeout'))
.map((res: Response) => res.json())
.catch(genericError$);
};
// get the token and build request
return token$
.map(jwt => {
if (options.body) {
if (typeof options.body !== 'string') {
options.body = JSON.stringify(options.body);
}
options.body = options.body.replace(/ /g, '').replace(/\r?\n|\r/g, '');
}
options.headers = new Headers({
'Content-Type': 'application/x-www-form-urlencoded, application/json'
});
if (jwt.Token) {
options.headers.append('Authorization', `Bearer ${jwt.Token}`);
}
Raven.captureMessage('request options', { level: 'info', environment: 'live', extra: options });
return options;
})
.switchMap(options => request$(options));
}
}
I am using:
Ionic 2.0.0-beta.11
Angular 2.0.0-rc.4
Most recent version of NativeStorage plugin from github
Devices with the error (only two examples, there are more):
Samsung SM-N910F (Webview: Chrome Mobile 53.0.2785, Android 6.0.1)
Samsung SM-G800F (Webview: Chrome Mobile 53.0.2785, Android 5.1.1)
If somebody's interested: The root cause was that people that upgraded Android somehow lost the chrome webview app and Angular was not working without one (of course). I solved it by packaging the crosswalk-webview in my app!

Categories

Resources