Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Android] - XMLHttpRequest ontimeout not fired #11666

Closed
sergop321 opened this issue Dec 29, 2016 · 9 comments
Closed

[Android] - XMLHttpRequest ontimeout not fired #11666

sergop321 opened this issue Dec 29, 2016 · 9 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@sergop321
Copy link

Timeouted XMLHttpRequest request do not call the timeout callback on android.
The request is being aborted (the onreadystatechange or onerror never get called after)
while in IOS the timeout event getting called as expected.

const request =  new XMLHttpRequest();

request.open('GET', "http://localhost:3333/", true);
request.timeout = 1000;
request.onabort = () => { console.log('abort', request); };
request.onerror = () => { console.log('error', request); };
request.onload = () => { console.log('load', request); };
request.onloadend = () => { console.log('loadend', request); };
request.onreadystatechange = () => { console.log('onreadystatechange', request); };
request.ontimeout = () => { console.log('ontimeout', request); };
request.send();

The server sleeps for 3 seconds to make sure the timeout occurs.

will print on Android

onreadystatechange XMLHttpRequest {UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4}
load XMLHttpRequest {UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4}
loadend XMLHttpRequest {UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4}

on Ios

onreadystatechange XMLHttpRequest {UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4}
ontimeout XMLHttpRequest {UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4}
loadend XMLHttpRequest {UNSENT: 0, OPENED: 1, HEADERS_RECEIVED: 2, LOADING: 3, DONE: 4}

Additional Information

  • React Native version: 0.39.2
  • Platform: Android
  • Operating System: MacOS
@rafaelbusetti
Copy link

+1

@Lxxyx
Copy link
Contributor

Lxxyx commented Feb 7, 2017

+1 same problem. but use axios

@Lxxyx
Copy link
Contributor

Lxxyx commented Feb 7, 2017

@sergop321 @OMegaTiger Do you resolve this problem?

@sergop321
Copy link
Author

I encounter the problem while using axios but after some investigation I tracked the issue to react native XMLHttpRequest.

I wasn't able to resolve the issue, but I did find out that it is not always happening, https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/js/XHRExampleOnTimeOut.js this example with timeout on in android works (it do not work if you change the domain)

I am not sure what exactly the issue it might be with localhost, or port or it might be with the way you holding the request on the server. @Lxxyx if you are using localhost try to make the request to a different domain it might help.

@Lxxyx
Copy link
Contributor

Lxxyx commented Feb 7, 2017

@sergop321 thank you, i'll try it.

@Lxxyx
Copy link
Contributor

Lxxyx commented Feb 10, 2017

Seems to be axios bug. When i set timeout to 10ms, timeout works for every request but when i set timeout to 3000ms or longer, timeout do not work.

@Lxxyx
Copy link
Contributor

Lxxyx commented Feb 12, 2017

@sergop321 I resolve this problem by use axios cancelToken but not timeout (I can not resolve react-native bugs).

Here is the code:

const TIMEOUT = 5000
function generateRequestCancelToken () {
  let cancelRequest

  return async (config: Axios.AxiosXHRConfigBase<any>) => {
    config.cancelToken = new axios.CancelToken((cancelExecutor) => {
      cancelRequest = cancelExecutor
    })

    setTimeout(() => {
      if (cancelRequest instanceof Function) {
        cancelRequest('ECONNABORTED')
      }
    }, TIMEOUT)

    return config
  }
}

const requestCancelToken = generateRequestCancelToken()
axiosInstance.interceptors.request.use(requestCancelToken, null)

When timeout, it will throw an error: { message: 'ECONNABORTED' }, then you can handle this error.

@sergop321
Copy link
Author

sergop321 commented Feb 12, 2017

Thanks @Lxxyx This is a specific workaround using axios but it probably should have a fix in the android code. this bug will persistent for different libraries as well.

@Lxxyx In the gist provided you always overriding the cancelToken, that mean you won't be able to cancel requests that are not timeouted (Which is probably one of the reasons you are using axios instead of fetch in the first place), you can solve this by creating a wrapper around every request that will generate the cancel token and pass it (Not using the axios interceptors) or by passing cancelExecuter inside the config object and before generating a new cancel token, check if one already exsists.

@vmatt
Copy link

vmatt commented May 2, 2017

I solved this problem with a setTimeout method. If the readyState is not DONE, call the request.abort() function.

setTimeout(() => {
    if (request.readyState !== XMLHttpRequest.DONE) {
        request.abort();
        callback("timeouterror");
    }
}, parseFloat(this.state.timeout));

thotegowda pushed a commit to thotegowda/react-native that referenced this issue May 7, 2017
Summary:
In the NetworkingModule, if the http request failed, we send a `didCompleteNetworkResponse` event with the error message, which is used on JS side to determine if the request was erroring. Currently we get the error message from `e.getMessage()`, however, not all exceptions have a message and it might therefore return null and thus resulting in no error on JS side. This change checks if the message is null and if so uses a default message.

In android send a request using XMLHttpRequest with a timeout set to a server that has a delay larger than the timeout (so we force the timeout to happen).

```
const request =  new XMLHttpRequest();
request.open('GET', "http://localhost:3000/", true);
request.timeout = 1000;
request.ontimeout = () => { console.log('ontimeout'); };
request.send();
```

See the timeout callback being called correctly.

Fixes facebook#11666
Closes facebook#13407

Differential Revision: D4963764

Pulled By: hramos

fbshipit-source-id: 61ffcef9e0594fe9bface24fdb8bde1e6eec3990
@facebook facebook locked as resolved and limited conversation to collaborators May 24, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 19, 2018
facebook-github-bot pushed a commit that referenced this issue Nov 14, 2018
Summary:
Fixes #11666 (Which was incorrectly closed)
Pull Request resolved: #22164

Differential Revision: D13057001

Pulled By: hramos

fbshipit-source-id: bcd53e893bc7c114f866e54938166b74b8ae0299
kelset pushed a commit that referenced this issue Nov 26, 2018
Summary:
Fixes #11666 (Which was incorrectly closed)
Pull Request resolved: #22164

Differential Revision: D13057001

Pulled By: hramos

fbshipit-source-id: bcd53e893bc7c114f866e54938166b74b8ae0299
t-nanava pushed a commit to microsoft/react-native-macos that referenced this issue Jun 17, 2019
Summary:
Fixes facebook#11666 (Which was incorrectly closed)
Pull Request resolved: facebook#22164

Differential Revision: D13057001

Pulled By: hramos

fbshipit-source-id: bcd53e893bc7c114f866e54938166b74b8ae0299
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants