使用Fetch执行超时错误 - React Native

时间:2017-02-09 22:03:25

标签: react-native fetch

我有一个正在运行的用户登录功能。但是,我想为fetch合并一个超时错误。有没有办法设置一个5秒左右的计时器,以便在这样的时间后停止尝试获取?否则,我只是在网络错误一段时间后得到一个红色屏幕。

  _userLogin() { 
    var value = this.refs.form.getValue();
    if (value) { // if validation fails, value will be null
    if (!this.validateEmail(value.email)) {
      Alert.alert(
          "Enter a valid email",
        )
  } else {
      fetch("http://51.64.34.134:5000/api/login", {       
        method: "POST", 
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        timeout: 5000, 
        body: JSON.stringify({
          username: value.email, 
          password: value.password, 
        })
      })
      .then((response) => response.json())
      .then((responseData) => {
        if (responseData.status == "success") {
        this._onValueChange(STORAGE_KEY, responseData.data.token)
        Alert.alert(
          "Login Success!",
        )
        this.props.navigator.push({ name: 'StartScreen'})
        } else if (responseData.status == "error") {
        Alert.alert(
          "Login Error",
          responseData.message
        )
        }
      })
      .done();
    }
  }},    

6 个答案:

答案 0 :(得分:2)

没有标准的方法来处理a timeout option isn't defined in the official spec yetThere is an abort defined您可以将自己的超时和Promise结合使用。例如,见herehere。我已经复制了示例代码,但还没有自己测试过。

// Rough implementation. Untested.
function timeout(ms, promise) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      reject(new Error("timeout"))
    }, ms)
    promise.then(resolve, reject)
  })
}

timeout(1000, fetch('/hello')).then(function(response) {
  // process response
}).catch(function(error) {
  // might be a timeout error
})

另一个选择是自己修改fetch.js模块,添加一个调用abort的超时,如here所示。

答案 1 :(得分:2)

这就是我要做的事情: (这是"泛型"我用来在我的应用上拨打所有电话的功能)

我创建了一个超时功能,除非之前被清除,否则将被触发,然后我在服务器响应中清除此超时

   const doFetch = (url, callback, data) => { 

    //... creating config obj here (not relevant for this answer)

  var wasServerTimeout = false;

  var timeout = setTimeout(() => {
    wasServerTimeout = true;
    alert('Time Out')
  } , 3000)


      fetch(HOST + url, config)
      .then((response) => { 

        timeout && clearTimeout(timeout); //If everything is ok, clear the timeout

    if(!wasServerTimeout){
        return response.json()
    } 
      })
      .then((response) => {  
              callback && callback( response.data || response ); 
         }).catch((err) => {

           timeout && clearTimeout(timeout); //If something goes wrong, clear the timeout

     if(!wasServerTimeout){
          //Error logic here
       }

         });
    }

答案 2 :(得分:1)

我通过使用2个promises之间的竞赛来解决这个问题,这个竞争被写为fetch的包装器。在我的情况下,我希望返回json的请求,所以也添加了。也许有更好的解决方案,但这对我来说是正确的!

包装器返回一个promise,只要没有代码错误就会解析。 您可以检查result.status中的“success”并从result.data中读取json数据。如果出现错误,您可以在result.data中读取确切的错误,并将其显示或记录在某处。这样你总能知道出了什么问题!

var yourFetchWrapperFunction = function(method, url, headers, body, timeout=5000){    
var timeoutPromise = new Promise(function(resolve,reject){
                        setTimeout(resolve, timeout, {status: 'error', code: 666, data: 'Verbinding met de cloud kon niet tot stand gebracht worden: Timeout.'});
                      });
    return Promise.race([timeoutPromise, fetch(connectionType + '://' + url, {method: method, headers: headers, body: body})]).then((result) => {
                        var Status = result.status;
                        return result.json().then(function(data){
                          if (Status === 200 || Status === 0) {
                            return {status: 'success', code: Status, data: data};
                          }
                          else {
                            return {status: 'error', code: Status, data: 'Error (' + data.status_code + '): ' + data.message};
                          }
                        },function (response) {
                          return {status: 'error', code: Status, data: 'json promise failed' + response};
                        }).catch((error) => {
                          return {status: 'error', code: 666, data: 'no json response'};
                        });
                      }, function(error){
                          return {status: 'error', code: 666, data: 'connection timed out'};
                      }).catch((error) => {
                          return {status: 'error', code: 666, data: 'connection timed out'};
                      });
}

答案 3 :(得分:1)

有一个npm软件包,称为react-native-fetch-polyfill。该程序包始终使用最后一个稳定的访存版本并实现超时。您还可以使用现代javascript async / await sintax。这是一个示例:

从“ react-native-fetch-polyfill”导入获取;

import fetch from 'react-native-fetch-polyfill';

async checkNetwork() {
    const url = `https://yoururl.org`;
    const requestInfo = {
      method: 'GET',
      headers: {
        'Accept': 'application/json',
        'Content-Type': 'application/json'
      },
      timeout: 2000  // here is the timeout
    }
    try {
      let data = await fetch(url, requestInfo);
      if (data.status == 200) {
        let json = await data.json();
        return json;
      } else {
        Alert.alert('Error','Error message')
      }
    } catch (e) {
         Alert.alert('Error','your timeout message')
    }
  }

答案 4 :(得分:0)

  

我可能迟到了,但是我编写了一个代码,该代码可以100%地使用提取超时API请求。

<?xml version="1.0" encoding="utf-8"?>
<nav modified="2019-05-29T06:10:36-07:00" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:noNamespaceSchemaLocation="navSrc.xsd">
<items>
<item id="100" appcode="My Accounts" href="launchapp? 
appcode=My+Accounts" onclick="" target="" disabled="false" label="My 
Accounts" locked="true" editable="true"/>
<item id="3000" appcode="Move Money" href="#" label="Move Money" 
locked="false" editable="true"/>
</items>
</nav>

您只需要将 <?xml version="1.0" encoding="UTF-8"?> <nav xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" modified="2019-05-29T06:10:36-07:00" xsi:noNamespaceSchemaLocation="navSrc.xsd"> <items> <item appcode="My Accounts" disabled="false" editable="true" href="launchapp?appcode=My+Accounts" id="100" label="My Accounts" locked="true" onclick="" target=""/> <item appcode="Move Money" editable="true" href="#" id="3000" label="Move Money" locked="false"/> </items> </nav> 传递给url,并将fetch_timeout(url, options) { let timeout = 1000; let timeout_err = { ok: false, status: 408 }; return new Promise(function (resolve, reject) { fetch(url, options).then(resolve, reject).catch(() => { alert('timeout.') }); setTimeout(reject.bind(null, timeout_err), timeout); }); } 传递给api-endpoint参数。

答案 5 :(得分:0)

// Wrapper function for fetch
const fetchSomething = async () => {
    let controller = new AbortController()
    setTimeout(() => controller.abort(), 3000);  // abort after 3 seconds
    const resp = await fetch('some url', {signal: controller.signal});
    const json = await resp.json();
    if (!resp.ok) {
        throw new Error(`HTTP error! status: ${resp.status}`);
    }
    return json;
}


// usage
try {
    let jsonResp = await fetchSomthing();
    console.log(jsonResp);
} catch (error) {
    if (error.name === 'AbortError') {
        console.log('Network Error');
    } else {
        console.log(error.message);
    }
}

我认为使用AbortController是终止fetch呼叫的推荐方法。上面的代码段处理以下情况:

  1. 如果网络正常,但是HTTP返回错误状态,则会记录消息“ HTTP错误!...”。
  2. 如果网络中断,setTimeout将在三秒钟后触发AbortController中止fetch。消息“网络错误”将被记录。
  3. 如果网络正常且HTTP响应良好,则将记录响应JSON。

使用AbortController中止fetch的文档是here