尝试使用 Axios 向 API 发送 POST 请求时,响应中的 'Access-Control-Allow-Credentials' header 是“ ”

'Access-Control-Allow-Credentials' header in the response is ' ' when trying to send a POST request to an API using Axios

我在 localhost:3000 中有一个 React 应用程序 运行,在 localhost:8000 中有一个 nodeJS-express 服务器,我需要向 jsreport 发送一个 POST 请求API,但是当我尝试发送请求时出现以下错误:

Access to XMLHttpRequest at 'http://localhost:5488/api/report' from origin 'http://localhost:3000' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Credentials' header in the response is '' which must be 'true' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.

Post 请求:

axios.defaults.withCredentials = true;

axios.post('http://localhost:5488/api/report',
{withCredentials: true, crossorigin: true},
{
  "template": {
    "content": "<h1>Hello {{foo}}</h1>",
    "engine": "handlebars",
    "recipe": "chrome-pdf"
  },
  "data": {
    "foo": "world"
  }
}).then((response)=> {
  fs.writeFileSync('/reports/report.pdf', response.content)
}).catch(function (error) {
  console.log('AXIOS error: '+ error);
  return 'errorReport'
})

Server.js:

var corsOptions = {
  origin: 'http://localhost:3000',
  credentials : true
 }
app.use(cors(corsOptions));
app.use((req, res, next) => {
  res.header('Access-Control-Expose-Headers', 'Origin, X-Requested-With, Content-Type, Accept');
  res.header("Access-Control-Allow-Origin", "http://localhost:3000");
  res.header("Access-Control-Allow-Credentials", true);
  res.header("Access-Control-Allow-Methods", "GET,PUT,POST,DELETE");
  res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
  const err = new Error('Not Found');
  err.status = 404;
  next(err);
})

我不明白为什么凭据为空如果我在 axios 中使用 .withCredentials 并在服务器中建立 headers 和 cors 配置。

更新 Server.js 如下

var corsOptions = {
  origin: 'http://localhost:3000',
  credentials : true
 }

app.use(cors(corsOptions));

app.use(function (req, res, next) { 
    res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');    
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS, PUT, PATCH, DELETE');    
    res.setHeader('Access-Control-Allow-Headers', 'X-Requested-With,content-type');   
    res.setHeader('Access-Control-Allow-Credentials', true);    
    next();
});

我使用了下一个代码而不是 axios 请求并且它起作用了:

fetch('http://localhost:5488/api/report', {
  method: 'POST',
  body: JSON.stringify(data),
  headers:{
    'Content-Type': 'application/json'
  },
  credentials: "same-origin",
}

将凭据设置为 "same-origin" 解决了问题,但由于我想使用 jsreport,我找到了一个包来简化此过程,而无需使用 fetch 或 axios。

import jsreport from 'jsreport-browser-client-dist'
jsreport.serverUrl = 'http://localhost:5488'
jsreport.render(document.getElementById('reportPlaceholder'), data)

使用 jsreport 方法我可以在反应组件中显示我的报告

<div id="reportPlaceholder">
      <p>there should be a report here...</p>
</div>

我一直在摆弄持久性用户会话一段时间,并且无法将 passport / passport-local(用于身份验证)、mongoose, express-sessionconnect-mongo(用于将会话存储在mongo).

@mshibl 评论帮助我更进一步,为 express 设置这些 cors 选项最终使 cookies 被正确传递。希望这可以帮助遇到类似问题的其他人

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

这对我有用

export default function({ $axios, redirect }, inject) {
  // Base URL
  const base = process.env.API_URL

  // Sett withCredentials on $axios before creating instance
  $axios.defaults.withCredentials = true

  // Create a custom axios instance
  const api = $axios.create({
    baseURL: base,
    responseType: 'json',
    timeout: 10000,
    // withCredentials: true,
    headers: {
      'X-Requested-With': 'XMLHttpRequest',
      'Content-Type': 'application/json'
    }
  })

  // Inject to context as $api
  inject('api', api)

在创建我自己的实例之前设置 defaults.withCredentials 为我解决了这个问题。