使用Fetch时出现超时错误- React Native

fkvaft9z  于 2022-12-30  发布在  React
关注(0)|答案(7)|浏览(334)

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

_userLogin() {
  var value = this.refs.form.getValue();
  if (value) {
    // if validation fails, value will be null
    if (!this.validateEmail(value.email)) {
      // eslint-disable-next-line no-undef
      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();
    }
  }
}
brtdzjyr

brtdzjyr1#

我做了一个ES6函数,将ES获取封装到一个promise中,如下所示:

export async function fetchWithTimeout(url, options, timeout = 5000) {
    return Promise.race([
        fetch(url, options),
        new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
    ]);
}

下面是如何使用它:

const requestInfo = {
    method,
    headers,
    body,
};
const url = 'http://yoururl.edu.br'
let data = await fetchWithTimeout(url, requestInfo, 3000);
uttx8gqw

uttx8gqw2#

// 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错误!...”。
1.如果网络中断,setTimeout将触发AbortController在三秒后中止fetch。将记录消息“网络错误”。
1.如果网络良好且HTTP响应良好,则将记录响应JSON。
使用AbortController中止fetch的文档为here

e5nszbig

e5nszbig3#

a timeout option isn't defined in the official spec yet . There is an abort defined没有标准的处理方法,你可以把它和你自己的超时和承诺一起使用。例如这里和这里看到的。我复制了示例代码,但还没有自己测试过。

// 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的超时,如下图所示。

rjee0c15

rjee0c154#

这是我绕过去的方法:(这是我用来在应用程序上进行所有调用的“通用”函数)
我创建了一个超时函数,除非之前清除,否则将触发该函数,然后我在服务器响应时清除此超时

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) => {
      //If something goes wrong, clear the timeout
      timeout && clearTimeout(timeout);
      if (!wasServerTimeout) {
        //Error logic here
      }
    });
};
kx5bkwkv

kx5bkwkv5#

我通过使用两个承诺之间的竞争解决了这个问题,写为一个关于获取的 Package 器。在我的例子中,我希望请求返回json,所以也添加了这一点。也许有一个更好的解决方案,但这对我来说是正确的!
Package 器返回一个承诺,只要没有代码错误,它就会解决问题。你可以检查result.status是否为“success”,并从www.example.com读取json数据result.data。如果有错误,你可以在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'};
    });
};
pinkon5k

pinkon5k6#

let controller = new AbortController()
      
      setTimeout( () => {
          controller.abort()
      }, 10000);    // 10,000 means 10 seconds

    return fetch(url, {
        method: 'POST',        
        headers: headers, 
        body: JSON.stringify(param),
        signal: controller.signal
    })

gcxthw6b

gcxthw6b7#

我可能会迟到,但我做了一个代码,这是100%的工作超时的API请求使用提取。

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传递给url,将body传递给options参数。

相关问题