最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Promise reject not triggering - Stack Overflow

programmeradmin4浏览0评论

I'm relatively new to Promises in js and am having trouble understanding why the following block of code does not run my catch function when the server responds with a 401 unauthorized.

loginUser(email, password).then((token) => {
  console.log("in then")
  //ipcRenderer.send('login-success', token)
}).catch(err => {
  console.log("in catch")   //not running
})

The loginUser function:

function loginUser(email, password) {
  let body = { email: email, password: password  }

  return fetch('http://localhost:3000/api/v1/sessions', {
    method: 'POST',
    body: JSON.stringify(body),
    headers: { 'Content-Type': 'application/json' }
    }).then(response => {
       return response.json().then(json => {
         console.log(response.ok) // false
         return response.ok ? json : Promise.reject(json)
    }).catch(err => {
      console.error(err)
    })
  })
}

Any help at all would be appreciated. Cheers

I'm relatively new to Promises in js and am having trouble understanding why the following block of code does not run my catch function when the server responds with a 401 unauthorized.

loginUser(email, password).then((token) => {
  console.log("in then")
  //ipcRenderer.send('login-success', token)
}).catch(err => {
  console.log("in catch")   //not running
})

The loginUser function:

function loginUser(email, password) {
  let body = { email: email, password: password  }

  return fetch('http://localhost:3000/api/v1/sessions', {
    method: 'POST',
    body: JSON.stringify(body),
    headers: { 'Content-Type': 'application/json' }
    }).then(response => {
       return response.json().then(json => {
         console.log(response.ok) // false
         return response.ok ? json : Promise.reject(json)
    }).catch(err => {
      console.error(err)
    })
  })
}

Any help at all would be appreciated. Cheers

Share Improve this question asked Jul 23, 2017 at 22:23 jmtibsjmtibs 2552 gold badges5 silver badges11 bronze badges 5
  • Does any of your code run? Are you sure it's not executing your then clause? What do you see in your console and network tab? – timothyclifford Commented Jul 23, 2017 at 22:27
  • @timothyclifford sry should have provided more details from the get-go. Code does execute. I see three things in my console when intentionally entering in a bad email/pass bo. I see the server response from fetch, 401 unauthorized, I see the actual error object from the console.error(err) in the catch of the fetch call, and I see the console.log output "in then", which I expect to be "in catch" – jmtibs Commented Jul 23, 2017 at 22:32
  • you are catching the error in login user. After catching, the promise is considered 'fixed' if it doesn't throw. – marzelin Commented Jul 23, 2017 at 22:32
  • @marzelin ah I see. That makes sense now. Thank you. – jmtibs Commented Jul 23, 2017 at 22:33
  • .catch(err => {console.error(err)} makes it so you will NEVER return a rejected promise because this takes a rejected promise and turns it into a resolved promise. If you want to log like this, then you have add throw err to the .catch() handler to rethrow the error and keep the promise rejected. Also, a 401 status is still a successful http request. The server was contacted and a response returns. That does not reject. So, you need to either check the status in your .then() handler or specifically change a non-2xxx response into a rejection yourself. – jfriend00 Commented Jul 24, 2017 at 0:00
Add a ment  | 

3 Answers 3

Reset to default 4

From fetch GitHub:

https://github./github/fetch/issues/201

Fetch API fails only if it can't make a request. And if it can, fetch will be executed successfully even if it has a bad status.

So it sounds like your .then( branch will be handling the 401 and you will need to handle it here.

.catch( will only execute if the request can't be made.

Promise.reject()
  .catch(() => console.log("rejection is caught in first `catch`"))
  .then(() => console.log("`catch` returns fulfilled  promise so `then` is executed"))
  .catch(() => console.log("this won't be executed"))

I see a couple problems here:

First, a 401 response ing back from a fetch() does not reject. That's a SUCCESSFUL http request. It contacted the server, sent the request and got the response. The fact that you got a 401 status back is up to your application how to handle. A 401 status does not reject.

From the MDN doc for fetch():

The Promise returned from fetch() won’t reject on HTTP error status even if the response is an HTTP 404 or 500. Instead, it will resolve normally (with ok status set to false), and it will only reject on network failure or if anything prevented the request from pleting.

Second, when you do this:

}).catch(err => {
  console.error(err)
})

You are catching a rejected promise, handling it and turning it into a resolved promise (just like a try/catch stops a thrown exception). So your function, as written, could never return a rejected promise). If you want to log like that, but preserve the rejected promise, then you need to rethrow the error:

}).catch(err => {
  console.error(err)
  throw err;
})

If you wanted a resolved promise only when you get valid data, you could specifically make the promise reject with other statuses or you could check for the response.ok from fetch and turn that into a rejection:

function loginUser(email, password) {
  let body = { email: email, password: password  }

  return fetch('http://localhost:3000/api/v1/sessions', {
    method: 'POST',
    body: JSON.stringify(body),
    headers: { 'Content-Type': 'application/json' }
    }).then(response => {
       // make sure that we actually got data
       if (!response.ok) {
          throw new Error(`No response.ok.  Got http status ${response.status}`);
       }
       return response.json().then(json => {
         console.log(response.ok) // false
         return response.ok ? json : Promise.reject(json)
    }).catch(err => {
      console.error(err);
      throw err;
    });
  })
}

Third, since the error you refer to is an authorization error, you should be warned that fetch() does not, by default, send any cookies so if you were relying on cookies for authentication, you will have to configure your fetch() request specifically to send cookies using the fetch option: credentials: 'include'.

发布评论

评论列表(0)

  1. 暂无评论