HTTP 请求的 headers 没有 Origin

问题描述 投票:0回答:1

为什么HTTP请求头没有Origin? 从前端向后端发出任何请求后,我面临 CORS 冲突。

我有两个项目。两者都位于一台服务器上,具有一个公共 IP,但域不同。

项目#1:

前端(React.js)
IP - 84.201.143.32
域名 - https://place.nomoredomains.xyz
后端(Node.js、express、mongoDB)
IP - 84.201.143.32
域名 - https://api.place.nomoredomains.xyz

项目#2:

前端(React.js)
IP - 84.201.143.32
域名 - https://ypdiploma.nomoreparties.co/
后端(Node.js、express、mongoDB)
IP - 84.201.143.32
域名 - https://api.ypdiploma.nomoreparties.co

这两个项目都通过 Nginx 运行。
这是站点可用/默认配置:

server {

      server_name api.place.nomoredomains.xyz;

   location / {
                proxy_pass http://localhost:3000;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
      }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/place.nomoredomains.xyz/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/place.nomoredomains.xyz/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {

      server_name place.nomoredomains.xyz;

      root /home/lexev/react-mesto-api-full-gha/frontend/build;

      location / {
        try_files $uri $uri/ /index.html;
      }

    listen 443 ssl; # managed by Certbot
     ssl_certificate /etc/letsencrypt/live/place.nomoredomains.xyz/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/place.nomoredomains.xyz/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}


server {

      server_name api.ypdiploma.nomoreparties.co;

      location / {
                proxy_pass http://localhost:3001;
                proxy_http_version 1.1;
                proxy_set_header Upgrade $http_upgrade;
                proxy_set_header Connection 'upgrade';
                proxy_set_header Host $host;
                proxy_cache_bypass $http_upgrade;
      }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/place.nomoredomains.xyz/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/place.nomoredomains.xyz/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}

server {

      server_name ypdiploma.nomoreparties.co;

      root /home/lexev/ypdiploma/movies-explorer-frontend/build;

      location / {
        try_files $uri $uri/ /index.html;
      }

    listen 443 ssl; # managed by Certbot
    ssl_certificate /etc/letsencrypt/live/place.nomoredomains.xyz/fullchain.pem; # managed by Certbot
    ssl_certificate_key /etc/letsencrypt/live/place.nomoredomains.xyz/privkey.pem; # managed by Certbot
    include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot

}


server {
    if ($host = place.nomoredomains.xyz) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


      listen 80;

      server_name place.nomoredomains.xyz;
    return 404; # managed by Certbot


}server {
    if ($host = api.place.nomoredomains.xyz) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


      listen 80;

      server_name api.place.nomoredomains.xyz;
    return 404; # managed by Certbot


}

server {
    if ($host = ypdiploma.nomoreparties.co) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


      listen 80;

      server_name ypdiploma.nomoreparties.co;
    return 404; # managed by Certbot


}


server {
    if ($host = api.ypdiploma.nomoreparties.co) {
        return 301 https://$host$request_uri;
    } # managed by Certbot


      listen 80;

      server_name api.ypdiploma.nomoreparties.co;
    return 404; # managed by Certbot


}

项目 #1 工作正常,并发送所有带有 Origin 标头的请求,但项目 #2 不发送任何 Origin 标头。因此,我遇到了项目 #2 的 CORS 冲突。

项目 #1 HTTP 请求:Network Tab from Chrome
项目 #2 HTTP 请求:Network Tab from Chrome

CORS 错误:screenshot

我想你可能还需要 corsHandler 中间件代码:

const allowedCors = [
  'https://ypdiploma.nomoreparties.co',
  'http://ypdiploma.nomoreparties.co',
  'https://ypdiploma.nomoreparties.co/',
  'http://ypdiploma.nomoreparties.co/',
  'http://localhost:3000',
];

const corsHandler = (req, res, next) => {
  const { origin } = req.headers;
  const { method } = req;

  const DEFAULT_ALLOWED_METHODS = 'GET,HEAD,PUT,PATCH,POST,DELETE';
  const requestHeaders = req.headers['access-control-request-headers'];

  if (allowedCors.includes(origin)) {
    res.header('Access-Control-Allow-Origin', origin);
    res.header('Access-Control-Allow-Credentials', true);
  }

  if (method === 'OPTIONS') {
    res.header('Access-Control-Allow-Methods', DEFAULT_ALLOWED_METHODS);
    res.header('Access-Control-Allow-Headers', requestHeaders);
    res.header('Access-Control-Allow-Credentials', true);
    return res.end();
  }

  return next();
};

module.exports = { corsHandler };

这是我的应用程序:

require('dotenv').config();
const express = require('express');
const mongoose = require('mongoose');
const cookieParser = require('cookie-parser');
const { errors } = require('celebrate');
const helmet = require('helmet');
const { requestLogger, errorLogger } = require('./middlewares/logger');
const { corsHandler } = require('./middlewares/cors');
const { limiter } = require('./middlewares/limiter');

const errorHandler = require('./middlewares/errorHandler');
const { MONGOOSE_DB } = require('./constants/constants');

const { PORT = 3001 } = process.env;

const app = express();
mongoose.connect(MONGOOSE_DB);

app.use(helmet());
app.use(corsHandler);
app.use(express.json());
app.use(cookieParser());
app.use(requestLogger);

app.use('/', limiter, require('./routes/index'));

app.use(errorLogger);

app.use(errors());
app.use(errorHandler);

app.listen(PORT);

最后从前端部分获取:

class MainApi {
  constructor() {
    this._baseUrl = 'https://api.ypdiploma.nomoreparties.co'
    this._headers = {
      'Content-Type': 'application/json',
    };
  }

  _getResponseData(res) {
    if (res.ok) {
      return res.json();
    } else {
      return Promise.reject(res);
    }
  }

  getUserinfo() {
    return fetch(this._baseUrl + '/users/me', {
      headers: this._headers,
      credentials: 'include',
    }).then((res) => this._getResponseData(res));
  }
}

const mainApi = new MainApi();

export default mainApi;

我尝试使用 Referer 标头实现 CORS 检查,但没有成功。我怀疑问题出在 NGINX 的默认配置中,但不幸的是我找不到哪里......

express nginx cors http-headers cross-domain
1个回答
0
投票

您的逻辑会添加

Access-Control-Allow-Credentials
标头两次,以响应从您允许的来源之一发出的
OPTIONS
请求:

  if (allowedCors.includes(origin)) {
    res.header('Access-Control-Allow-Origin', origin);
    res.header('Access-Control-Allow-Credentials', true); // added once
  }

  if (method === 'OPTIONS') {
    res.header('Access-Control-Allow-Methods', DEFAULT_ALLOWED_METHODS);
    res.header('Access-Control-Allow-Headers', requestHeaders);
    res.header('Access-Control-Allow-Credentials', true); // added twice
    return res.end();
  }

您应该抵制通过手动设置 CORS 响应标头来“手动”实现 CORS 的诱惑;除非您非常熟悉 CORS 协议,否则这样做很容易出错。 Express.js 有一个 CORS 中间件;学习(安全地)配置它并使用它。

另请注意,将

http://ypdiploma.nomoreparties.co/
https://ypdiploma.nomoreparties.co/
列为允许的来源是不好的:这两个值无效 Web 来源,因为 来源不包含路径

© www.soinside.com 2019 - 2024. All rights reserved.