fetch: Getting cookies from fetch response

2020-08-25 05:28发布

问题:

I'm trying to implement client login using fetch on react.

I'm using passport for authentication. The reason I'm using fetch and not regular form.submit(), is because I want to be able to recieve error messages from my express server, like: "username or password is wrong".

I know that passport can send back messages using flash messages, but flash requires sessions and I would like to avoid them.

This is my code:

fetch('/login/local', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      body: JSON.stringify({
        username: this.state.username,
        password: this.state.password,
      }),
    }).then(res => {
      console.log(res.headers.get('set-cookie')); // undefined
      console.log(document.cookie); // nope
      return res.json();
    }).then(json => {
      if (json.success) {
        this.setState({ error: '' });
        this.context.router.push(json.redirect);
      }
      else {
        this.setState({ error: json.error });
      }
    });

The server sends the cookies just fine, as you can see on chrome's dev tools:

But chrome doesn't set the cookies, in Application -> Cookies -> localhost:8080: "The site has no cookies".

Any idea how to make it work?

回答1:

The problem turned out to be with the fetch option credentials: same-origin/include not being set. As the fetch documentation mentions this option to be required for sending cookies on the request, it failed to mention this when reading a cookie.

So I just changed my code to be like this:

fetch('/login/local', {
      method: 'POST',
      headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
      },
      credentials: 'same-origin',
      body: JSON.stringify({
        username: this.state.username,
        password: this.state.password,
      }),
    }).then(res => {
      return res.json();
    }).then(json => {
      if (json.success) {
        this.setState({ error: '' });
        this.context.router.push(json.redirect);
      }
      else {
        this.setState({ error: json.error });
      }
    });


回答2:

I spent a long time but nothing worked for me.

after trying several solutions online this one worked for me.

Hopefully it will work for you too.

{
  method: "POST",
  headers: {
    "content-type": "API-Key",
  },
  credentials: "include",
}


回答3:

From Differences from jQuery section of https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API

  • fetch() won't receive cross-site cookies. You can’t establish a cross site session using fetch(). Set-Cookie headers from other sites are silently ignored.
  • fetch() won’t send cookies, unless you set the credentials init option. Since Aug 25, 2017: The spec changed the default credentials policy to same-origin. Firefox changed since 61.0b13.)