我正在使用 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 中间件,但没有成功。
以下代码也将利用代码顺序执行相同的操作。 在加载全球 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'));
我找到原因了。原因是客户端路由包含服务路由。客户端路由是/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;