让Axios自动在请求中发送cookies

310

我使用 Axios 从客户端向我的 Express.js 服务器发送请求。

我在客户端上设置了一个 cookie,并且希望在所有的 Axios 请求中读取该 cookie,而无需手动将它们添加到请求中。

这是我的客户端请求示例:

axios.get(`some api url`).then(response => ...

我试图在我的Express.js服务器中使用这些属性来访问头文件或cookie:

req.headers
req.cookies

它们两个都没有包含任何cookie。我正在使用cookie解析器中间件:

app.use(cookieParser())

如何让Axios自动在请求中发送cookies?

编辑:

我在客户端设置cookie的方法如下:

import cookieClient from 'react-cookie'

...
let cookie = cookieClient.load('cookie-name')
if(cookie === undefined){
      axios.get('path/to/my/cookie/api').then(response => {
        if(response.status == 200){
          cookieClient.save('cookie-name', response.data, {path:'/'})
        }
      })
    }
...

虽然它也使用了 Axios,但这与问题无关。我只是想在设置 cookie 后将 cookie 嵌入到所有请求中。


1
你是如何在客户端设置cookie的?请给出代码示例 :) - Tzook Bar Noy
@TzookBarNoy 在问题中添加了代码。 - Kunok
2
Cookie是由服务器使用Set-Cookie设置的,而不是由客户端设置的。我猜你的意思是在客户端读取Cookie。根据Cookie协议,客户端应该在其请求中包含一个Cookie头,以向Cookie发行服务器发送请求。 - Hans Poo
看这个 https://dev59.com/qVQJ5IYBdhLWcg3wbFMW#55804086 - Ender Bonnet
21个回答

575

您可以使用withCredentials属性。

除非在发出请求之前将 withCredentials 设置为 true,否则来自不同域的 XMLHttpRequest 不能为其自己的域设置 cookie 值。

axios.get(BASE_URL + '/todos', { withCredentials: true });

同时也可以强制要求在每个 Axios 请求中添加凭据

axios.defaults.withCredentials = true

或者使用以下代码为Axios请求中的一些凭证进行身份验证:

Or using credentials for some of the Axios requests as the following code

const instance = axios.create({
   withCredentials: true,
   baseURL: BASE_URL
})
instance.get('/todos')

73
请注意,仅当响应标头中的 Access-Control-Allow-Origin 未设置为通配符 (*) 时,此方法才有效。 - Jerry Zhang
20
响应需要将Access-Control-Allow-Origin的值设置为您想要从中进行XHR请求的域。例如,https://a.com是服务器,https://b.com是客户端,并且https://b.com加载在某人的浏览器中,并使用XMLHTTPRequesthttps://a.com发出请求。另外,在https://a.com中初始化的XMLHTTPRequest要设置withCredential: true,还需要配置服务器 - https://b.com,以使响应标头包含Access-Control-Allow-Origin: https://a.com - Jerry Zhang
4
你是说你的示例中,https://b.com 代表客户端,因此应该在 b 而不是 a 中启动 XMLHTTPRequest 吗? - atjua
2
此外,请确保设置 cookie 的 POST 请求也包括 "withCredentials: true",而不仅仅是您随后的 GET 请求。 - rantao
1
可能与@rantao的评论有关。但请确保在接收cookie的调用中也添加withCredentials:true。否则,您进行的下一次调用将不使用检索到的cookie。 - hwcverwe
显示剩余6条评论

72

简述:

{ withCredentials: true }axios.defaults.withCredentials = true


Axios文档中说明

withCredentials: false, // 默认设置

withCredentials 表示是否使用凭证进行跨站点访问控制请求

如果您在请求中传递 { withCredentials: true },它应该可以工作。

更好的方法是将 withCredentials 设置为 trueaxios.defaults

axios.defaults.withCredentials = true


22
在每个请求中发送凭据是不良的做法。这些控件有其存在的原因。与其他服务通信时,发送所有 cookie(无论使用与否)容易被利用。 - colm.anseo
17
只有将服务器域作为其域的cookie才会被发送。(默认情况下,它们也不会发送到任何子域中,并且可以根据路径进行进一步过滤)。实际上,我们只发送由服务器设置的服务器cookie。 - M3RS
你知道在客户端是否可以更改(例如删除)由服务器设置的cookie吗? - Zennichimaro
1
@colm.anseo 我相信这个设置默认是关闭的,因为浏览器通常会默认阻止所有的CORS。大多数人不需要它,因此默认设置是这样的 - 为了服务于大多数人。那些需要不同行为的人必须通过调整设置来显式地请求它。默认情况下严格,如果你知道自己在做什么可以放松一下它。 - avepr

30

在Express响应中设置必要的标头也很重要。以下是对我有效的标头:

app.use(function(req, res, next) {
  res.header('Access-Control-Allow-Origin', yourExactHostname);
  res.header('Access-Control-Allow-Credentials', true);
  res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  next();
});

为了我(使用Node.js 6.9与Express 4.16,Chrome 63)而言,将**X-PINGOTHER添加到Access-Control-Allow-Headers已成为强制要求。请查看JakeElder**在此GitHub问题中的帖子:https://github.com/axios/axios/issues/191#issuecomment-311069164 - Maxime Pacary
这是必要的,以及在我的前端axios配置中添加axios.defaults.withCredentials = true;。一旦删除了package.json中的create-react-app代理,我们需要启用withCredentials,并在我们的express应用程序中包含上述中间件。谢谢。 - jboxxx
如果请求来自localhost:3000,这个代码是否有效? - Koala

27
所以我遇到了完全相同的问题,花了大约6个小时的时间搜索,我有
withCredentials: true 但是浏览器直到某种奇怪的原因我想到重新配置设置之前仍然没有保存cookie。
Axios.post(GlobalVariables.API_URL + 'api/login', {
    email,
    password,
    honeyPot
}, {
    withCredentials: true,
    headers: {
        'Access-Control-Allow-Origin': '*', 
        'Content-Type': 'application/json'
    }
});

似乎你应该始终先发送'withCredentials'键。

5
哇塞,伙计!我被这个问题困扰了好久,现在终于在互联网上找到了我最喜欢的答案。非常感谢!如果有人想知道为什么他们的GET请求返回isAuthenticated的值为true,但是他们的POST请求没有,那么你的POST请求必须格式化如下:axios.post(URL, {data}, {withCredentials: true})。而你的GET请求允许withCredentials随数据一起发送:axios.get(URL, {data, withCredentials: true})。至少对于我在React -> Express操作中是这样的。 - DORRITO
这是答案的必要部分。 - Maxim Zhukov
我失去了3天的时间,但现在仍然成功,添加任何选项。 - May'Habit
@DORRITO你的回答让我很开心。非常感谢。订单是最重要的事情。在POST请求中,withCredentials: true应该始终放在数据后面。在GET请求中,这并不是强制性的。 - Pramod Kishore
我认为withCredentials不需要在第三个参数中排在首位,但它只需要是第三个参数的一部分,而不是数据所在的第二个参数。 - kevlar
@kevlar 我已经编写 JavaScript 10 年以上了,在我的工作生涯中从未遇到过这种情况哈哈,但由于某种原因,在 headers 下面使用 withCredentials 不起作用,将其移动到上面就可以了...现在,这不是我第一次没有保存更改,突然保存它使其工作,改变顺序毫无意义...但这是一个好答案,post 和 get 是不同的。 - Luigi Cordoba Granera

18

我对Axios不熟悉,但据我所知,在JavaScript和Ajax中有一个选项

withCredentials: true

这将自动将 cookie 发送到客户端。例如,passportjs 也会在服务器上设置 cookie 来生成此场景。


1
我进行了设置但是没有任何变化,我在请求中看到响应cookie,但为什么我不能在存储中看到它?这就是我无法发送它的原因吗? - May'Habit
以上标志用于在请求中自动添加cookie(仅适用于您的域)。它与存储无关(我认为您指的是本地存储)。您需要从本地存储中读取它并手动发送。 - RITESH ARORA
我知道,但我添加了它却没有任何反应,cookie无法发送到服务器。 - May'Habit

15
你可以使用withCredentials属性在请求中传递cookies。
axios.get(`api_url`, { withCredentials: true })

通过设置{ withCredentials: true },您可能会遇到跨域问题。为了解决这个问题,您需要使用

expressApp.use(cors({ credentials: true, origin: "http://localhost:8080" }));

在这里,您可以了解 withCredentials


13

在2022年,Fatih的回答仍然有效且很棒。

同时,axios.defaults.withCredentials = true也能解决问题。

看起来,在单独的axios调用中传递{ withCredentials: true }已被弃用。


{ withCredentials: true } works perfectly fine in axios ^0.24.0 - avalanche1

11

对我有效的方法:

客户端:

import axios from 'axios';

const url = 'http://127.0.0.1:5000/api/v1';

export default {
  login(credentials) {
    return axios
      .post(`${url}/users/login/`, credentials, {
        withCredentials: true,
        credentials: 'include',
      })
      .then((response) => response.data);
  },
};
注意:凭证将成为POST请求的主体,在这种情况下,是用户登录信息(通常从登录表单中获取):
{
    "email": "user@email.com",
    "password": "userpassword"
}

服务器端:

const express = require('express');
const cors = require('cors');

const app = express();
const port = process.env.PORT || 5000;

app.use(
  cors({
    origin: [`http://localhost:${port}`, `https://localhost:${port}`],
    credentials: 'true',
  })
);

1
login函数的credentials参数应该填写什么内容? - geoidesic
在您的 axios.post 中,withCredentials: true 是否可以取代 credentials: 'include' 的需要?我在 axios 文档中没有看到后者选项:https://axios-http.com/docs/req_config。 - kevlar

8
如何让Axios自动发送请求中的cookie?
设置 axios.defaults.withCredentials = true; 或者对于某些特定的请求,您可以使用axios.get(url,{withCredentials:true}) 如果您的 “Access-Control-Allow-Origin” 设置为通配符(*),则会出现CORS错误。因此,请确保指定请求源的URL。
例如:如果发出请求的前端运行在 localhost:3000 上,则将响应标头设置为
res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');

也设置

res.setHeader('Access-Control-Allow-Credentials',true);

7

对于仍无法解决此问题的人,这个答案帮了我大忙。 stackoverflow answer: 34558264

简而言之: 我们需要在GET请求和POST请求(获取cookie)中都设置{withCredentials: true},无论是使用axios还是fetch。


2
这非常重要。我在我的代码中忽略了这一点,花了很多时间想知道为什么GET请求中的{ withCredentials: true }没有任何效果。 - yogmk
1
非常重要!有很多关于在请求配置中添加 withCredentials: true 的讨论,但不是这个细节。我花了将近2天的时间来解决这个问题,直到我偶然发现了这个。 - rantao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接