如何在 Node.js/Express 服务器中禁用特殊路由的 CORS 策略?

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

我正在使用 Node.js/Express 开发后端服务器,我想创建一个每个人都可以访问的外部 API。因此,我需要禁用外部 API 的 CORS 策略,但保留除外部 API 之外的所有其他 API 的策略。

这是我当前的server.js。

import path from 'path';
import cors from 'cors';
import nocache from 'nocache';
import express from 'express';
import mongoose from 'mongoose';
import { fileURLToPath } from 'url';
import bodyParser from 'body-parser';
import Router from './routes/index.js';
import PaymentController from './controllers/client/payment.controller.js';

// Get the directory name of the current module
const __dirname = path.dirname(fileURLToPath(import.meta.url));

mongoose.connect(process.env.DB)
    .then(() => {
        console.log(`Database connected successfully ${process.env.DB}`);
    })
    .catch((error) => console.log(error));

const app = express();

app.use(nocache());

// Combine to frontend for production
if (process.env.MODE == 'production') {
    app.use(express.static(path.join(__dirname, '../production/build')));
} else if (process.env.MODE == 'staging') {
    app.use(express.static(path.join(__dirname, '../staging/build')));
}

const allowedOrigins = [
    'http://localhost:3000'
];

const corsOptions = {
    origin: function (origin, callback) {
        if (!origin) return callback(null, true);
        if (allowedOrigins.indexOf(origin) !== -1) {
            callback(null, true);
        } else {
            callback(new Error('Not allowed by CORS'));
        }
    },
    methods: 'GET, OPTIONS',
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true,
};

// Apply CORS to most routes
app.use(cors(corsOptions));

app.post('/v1/api/webhook', express.raw({ type: 'application/json' }), PaymentController.handleSubscriptionEvent);

app.use(
    bodyParser.json({
        limit: '15360mb',
        type: 'application/json',
    })
);

app.use(
    bodyParser.urlencoded({
        limit: '15360mb',
        extended: true,
        parameterLimit: 5000000,
        type: 'application/json',
    })
);

app.use('/v1/', Router);

// Combile to frontend for production
if (process.env.MODE == 'production') {
    app.get('*', (req, res) => {
        res.sendFile(path.resolve(__dirname, '../production/build', 'index.html'));
    });
} else if (process.env.MODE == 'staging') {
    app.get('*', (req, res) => {
        res.sendFile(path.resolve(__dirname, '../staging/build', 'index.html'));
    });
}

const port = process.env.MODE === 'production' || process.env.MODE === 'staging' ? 3000 : 9200;
const runningMessage = 'Server is running on port ' + port;

app.listen(port, () => {
    console.log(runningMessage);
});

这是路由器

import express from 'express';
import AdminRouter from './admin.router.js';
import ClientRouter from './client.router.js';
import ServiceRouter from './service.router.js';

const router = express.Router();

router.use('/api/admin', AdminRouter);
router.use('/api', ClientRouter);
router.use('/api/service', ServiceRouter);

export default router;

正如您在我的代码中看到的,我有一个 allowedOrigins 数组,我想对 allowedOrigins 中包含的源禁用 CORS 策略。但对于外部 API,我想禁用所有来源的 CORS 策略。

为此,我尝试仅为外部 API 设置 cors 中间件,但没有成功。

node.js express cors
2个回答
0
投票

以下代码也将利用代码顺序执行相同的操作。 在加载全球 CORS 之前,会对任何起点的路线进行编码。

服务器.js

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

app.get('/open', (req, res) => {
  res.send(
    `CORS response : Access-Control-Allow-Origin ${res.getHeader(
      'Access-Control-Allow-Origin'
    )}`
  );
});

app.use(
  cors({
    origin: 'an allowed origin',
  })
);

app.get('/restricted', (req, res) => {
  res.send(
    `CORS response : Access-Control-Allow-Origin ${res.getHeader(
      'Access-Control-Allow-Origin'
    )}`
  );
});

app.listen(3000, () => console.log('L@3000'));

0
投票

我找到原因了。原因是客户端路由包含服务路由。客户端路由是/api,服务路由是/api/service,所以/api/*路由将首先传递客户端路由的中间件。这就是我添加子前缀的原因,以便客户端路由更新为 /api/client。然后,我更新了 corsOptions,如下所示。

import cors from 'cors';
import express from 'express';
import role from '../services/role.js';
import auth from '../services/auth.js';
import AdminRouter from './admin.router.js';
import ClientRouter from './client.router.js';
import ServiceRouter from './service.router.js';

const router = express.Router();

const allowedOrigins = ['https://gallerai.ai', 'https://gallerai-staging-v1.gallerai.ai', 'http://localhost:3000', 'http://localhost:3001'];
const corsOptions = {
    origin: function (origin, callback) {
        if (!origin) return callback(null, true);
        if (allowedOrigins.includes(origin)) {
            callback(null, true);
        } else {
            callback(new Error('Not allowed by CORS'));
        }
    },
    methods: 'GET, POST, PUT, DELETE, OPTIONS',
    allowedHeaders: ['Content-Type', 'Authorization'],
    credentials: true,
};

// Apply CORS to specific routes with configured options
router.use('/api/admin', cors(corsOptions), auth, role, AdminRouter);
router.use('/api/client', cors(corsOptions), ClientRouter);

// Explicitly allow all CORS for /api/service/*
router.options('/api/service/', cors()); // Handle pre-flight OPTIONS requests
router.use('/api/service/', cors(), (req, res, next) => {
    res.header('Access-Control-Allow-Origin', '*'); // Allow all origins explicitly
    res.header('Access-Control-Allow-Headers', 'Origin, X-Requested-With, Content-Type, Accept, Authorization, X-Api-Key');
    res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
    next();
}, ServiceRouter);

export default router;
© www.soinside.com 2019 - 2024. All rights reserved.