NodeJS 无法在Express和React中设置浏览器中的Cookie

piv4azn7  于 2023-06-22  发布在  Node.js
关注(0)|答案(2)|浏览(164)

我试图通过cookie在浏览器中存储JWt令牌。
Axios对前端的调用如下:

const accessToken = jwt.sign({ email }, process.env.ACCESS_TOKEN_SECRET);

console.log(accessToken)

res.cookie('jwt', accessToken, { httpOnly: true })
// console.log("Cokkie set is", cookie);
res.json({ message: 'Logged in successfully' });

在express中发布请求/登录路由如下:

const res = await axios.post(
  `${process.env.REACT_APP_API_URL}/login`,
  {
    email: loginInputs.email,
    password: loginInputs.password,
  },
  {
    // credentials: 'include',
    withCredentials: true,
  }
)

CORS策略设置如下:

const corsOptions = {
  origin: process.env.FRONTEND_URL,
  credentials: true,
  optionsSuccessStatus: 200,
  // exposedHeaders: \['Set-Cookie', 'Date', 'ETag'\]
};

app.use(cors(corsOptions));
app.options('\*', cors(corsOptions))

这段代码在Postman中运行良好,正在设置cookie,但在浏览器中抛出以下错误。目前客户端和服务器都在本地主机上工作!
login:1 CORS策略已阻止从源“http://localhost:3000”访问位于“http://localhost:8080/login”的XMLHttpRequest:对印前检查请求的响应未通过访问控制检查:当请求的凭据模式为“include”时,响应中“Access-Control-Allow-Origin”标头的值不能为通配符“*”。XMLHttpRequest发起的请求的凭据模式由withCredentials属性控制。
我尝试了Express Session Cookie Not Being Set when using React Axios POST Request中提到的所有方法,但无法解决错误。

liwlm1x9

liwlm1x91#

cors中间件的origin配置应为http://localhost:3000,增加http方案。参见Origin文档,有效的origin语法为:

Origin: null
Origin: <scheme>://<hostname>
Origin: <scheme>://<hostname>:<port>

通知浏览器允许来自源https://developer.mozilla.org的请求代码访问资源的响应将包括以下内容:

Access-Control-Allow-Origin: https://developer.mozilla.org

如果服务器向浏览器发送下面的响应头。

Access-Control-Allow-Origin: localhost:3000

运行在http://localhost:3000上的客户端向http://localhost:8080/api/login发送HTTP请求,请求头Origin将是:

Origin: http://localhost:3000

Access-Control-Allow-OriginOrigin不匹配,则用户代理将抛出CORS错误。
Origin请求头由浏览器自动添加到HTTP请求中。
如果用户代理需要请求包含在页面中的资源,或者由它执行的脚本获取的资源,则页面的origin可以包括在请求中。
但您的错误消息是:当请求的凭据模式为'include'时,响应中'Access-Control-Allow-Origin'头的值不能为通配符'*'
如果您想将cookie从客户端发送到服务器,请使用fetch选项。然后不要将origin设置为通配符'*',而将credentials: true设置为cors中间件。
例如
server.ts

import express from 'express';
import cors from 'cors';

const app = express();

const corsOptions = {
  // set origin to a specific origin.
  origin: 'http://localhost:3000',
  
  // or, set origin to true to reflect the request origin
  //origin: true,

  credentials: true,
  optionsSuccessStatus: 200,
};

app.use(cors(corsOptions));

app.post('/api/login', (req, res) => {
  res.cookie('jwt', '123', { httpOnly: true })
  res.status(200).json({ message: 'Logged in successfully' });
})

app.listen(8080, () => {
  console.log('Example app listening on port 8080!')
})

client/index.html

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>

<body>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/axios/1.4.0/axios.min.js"
    integrity="sha512-uMtXmF28A2Ab/JJO2t/vYhlaa/3ahUOgj1Zf27M5rOo8/+fcTUVH0/E0ll68njmjrLqOBjXM3V9NiPFL5ywWPQ=="
    crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <script>
    window.onload = function () {
      // use fetch
      fetch('http://localhost:8080/api/login', { method: 'POST', credentials: 'include' }).then(res => res.json()).then(data => {
        console.log(data)
      })

      // use axios
      axios.post('http://localhost:8080/api/login', {
        withCredentials: true
      }).then(res => {
        console.log(res.data)
      })
    }
  </script>
</body>

</html>

启动API服务器:

$ npx ts-node server.ts 
Example app listening on port 8080!

启动Web服务器:

$ npx http-server -p 3000 ./client/
Starting up http-server, serving ./client/
Available on:
  http://127.0.0.1:3000
  http://192.168.174.79:3000

使用URL访问前端:http://localhost:3000
控制台日志:

{message: 'Logged in successfully'}
sqougxex

sqougxex2#

我意识到我已经使用了两次app.use(cors())。后端server.js文件具有

app.use(cors(); // ......(1)

const corsOptions = {
    origin: process.env.FRONTEND_URL,
    credentials: true,
    optionsSuccessStatus: 200,
};
app.use(cors(corsOptions)); // ......(2)

由于(1)在(2)之前执行,所以抛出错误。代码现在运行得很好,代码部分只在(2)中。
注意:一定要确保代码片段的顺序。小错误,但有时很难通过它!

相关问题