【问题标题】:How do I deal with CORS problem for Angular app deployed on heroku with a Postgres express backend?如何使用 Postgres express 后端部署在 heroku 上的 Angular 应用程序的 CORS 问题?
【发布时间】:2020-08-06 23:38:36
【问题描述】:

我正在将我的 Angular 应用程序和 Postgres Express 后端部署到 heroku,以允许他们相互交谈。我现在遇到的一个大问题是,每当我尝试使用 fetch 方法时,它都会说我需要启用 CORS 或一个标题。我已经在下面的快递后端设置了它:

const app = express();
const cors = require('cors');
const port = process.env.PORT || 5000;
const Pool = require('pg').Pool;
const transRoutes = require('./transactions');
const groupsRoutes = require('./budget-group');
const itemsRoutes = require('./budget_item');
const accRoutes = require('./account');

app.use(cors({origin: '*'})); //I also tried cors()
app.use(express.json());
app.use('/transactions', transRoutes);
app.use('/groups', groupsRoutes);
app.use('/items', itemsRoutes);
app.use('/accounts', accRoutes);
app.use(function (req, res, next) {
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    next();
 })

const pool = new Pool({
    connectionString: process.env.DATABASE_URL,
    ssl: {
        rejectUnauthorized: false
    }
});

app.get('/', (req, res) => {
    res.send('Welcome to your server.');
});

app.get('/users', async (req, res) => {
    try {
        const getAllUsers = await pool.query("SELECT * FROM users");
        res.json(getAllUsers);
    } catch (err) {
        console.log(err);
    }
});

app.get('/login/:username/:password', async (req, res) => {
    try {
        const getUser = await pool.query("SELECT * FROM users WHERE username = $1 AND password = $2",
        [
            req.params.username,
            req.params.password
        ]);
        res.json(getUser.rows);
    } catch (err) {
        console.log(err);
    }
});

//More routes omitted for brevity

app.listen(port, () => {console.log(`Listening on port ${port}`)});

我认为我的代码对于后端来说很好,所以我觉得 Angular 代码是问题所在,但我不明白如何解决它。我是否必须为每个完成的 fetch 方法手动添加一个标头才能拥有 CORS 功能,或者我是否必须使用某种我找到但太困惑如何去做的代理?

我做的一个 fetch 方法的例子如下:

fetch(`https://name-redacted.herokuapp.com/login/${this.username}/${this.password}`, {
        method: 'GET',
        headers: {'Content-Type': 'application/json'}
      }).then(res => res.json())
      .then(info => {
        if (info.length === 0) {
          this.failedAuth = true;
        } else {
          this.infoService.setUpLoginInfo(info[0]);
          this.router.navigateByUrl('/instructions');
        }
      });

对于部署角度部分,我遵循了以下指南: https://youtu.be/KVFrTf4VD2o 我只是认为这可能很重要,因为它使用快速服务器来提供文件,而不是在构建应用程序后执行 ng serve。

编辑: 对于 CORS 错误:CORS 策略已阻止从源“https://app-project.herokuapp.com”获取“https://app-backend.herokuapp.com/register”的访问权限:没有“访问权限-请求的资源上存在 Control-Allow-Origin' 标头。如果不透明的响应满足您的需求,请将请求的模式设置为“no-cors”以获取禁用 CORS 的资源。

标题: Access-Control-Allow-Headers:Origin、X-Requested-With、Content-Type、Accept Access-Control-Allow-Methods 未显示。

【问题讨论】:

  • 出于安全考虑,您确定在 URL 中传递您的用户名和密码是个好主意吗?
  • 更符合您的问题,但是,您是否尝试过使用 Postman 或 Insomnia 之类的方式调用端点来验证您的端点是否实际设置了这些 CORS 标头?
  • 刚才我用邮递员做的时候,对于标题,它显示:Access-Control-Allow-Origin: '*'。还有什么需要展示的吗?
  • Access-Control-Allow-Headers 和 Access-Control-Allow-Methods 标头是什么样的?另外,CORS 错误到底说明了什么?
  • TLDR 如果浏览器说不存在访问控制标头...不存在访问控制标头。这表明您设置它们的中间件没有被击中......通常这表明您有中间件和路由乱序,或者您的中间件逻辑不正确。

标签: node.js angular express cors


【解决方案1】:

您的服务器可能还没有准备好处理飞行前请求。您似乎没有任何路由可以处理飞行前请求的 OPTIONS HTTP 方法。关于 CORS 的 Express 文档在 how to handle pre-flight requests 上有一个示例

根据文档,在所有请求上启用它的最简单方法是配置一个处理 OPTIONS 的路由:

app.options('*', cors())

【讨论】:

    【解决方案2】:

    我能够弄清楚如何解决我的问题。 @WiktorZychla 的评论是正确的,因为任何带有凭据的请求都会导致 * 不起作用。 Source 为了解决这个问题,我发现了他们提出的另一个讨论:

    const allowedOrigins = ['https://someapp.com'];
    app.use(cors({
        credentials: true,
        origin: (origin, callback) => {
          if (allowedOrigins.includes(origin)) {
            callback(null, true) 
          } else {
            callback(new Error(`Origin: ${origin} is now allowed`))
          }
        }
      }));
    

    您首先创建一个 allowedOrigins 数组来放置您用于访问 API 的任何 url。然后让您的服务器使用允许凭据的 cors 对象,然后检查请求的来源。如果 origin 存在于数组中,那么它将返回一个回调,允许每个请求工作。

    另外,如果你有单独的路线,如下所示:

    const transRoutes = require('./transactions');
    const groupsRoutes = require('./budget-group');
    const itemsRoutes = require('./budget_item');
    const accRoutes = require('./account');
    app.use('/transactions', transRoutes);
    app.use('/groups', groupsRoutes);
    app.use('/items', itemsRoutes);
    app.use('/accounts', accRoutes);
    

    然后在每个路由文件中,您需要复制我在顶部的cors信息并进行更改,以便每个路由器都配置了cors。可能还有其他解决方案,但这对我来说是最快的。

    【讨论】:

      猜你喜欢
      • 2018-11-19
      • 2022-07-12
      • 2020-11-01
      • 2020-05-27
      • 2020-07-14
      • 2020-03-13
      • 2020-08-27
      • 2021-09-02
      • 2017-04-15
      相关资源
      最近更新 更多