Express CORS 有时有效,有时无效
Express CORS sometimes works and sometimes doesn't
我有一个 Express API 托管在位于 main-domain.tld/api/
的 ngnix 上,还有一个位于 sub.main-domain.tld
的管理面板将请求发送到我的 API.
当我尝试从我的管理面板向我的 API 发送请求时,我收到 CORS 错误,70% 的时间与我请求的路由和使用的方法无关(POST、获取等)。
我不明白两件事:
- 首先是为什么我在启用所有功能后收到 CORS 错误
源自我的 API 源代码。
- 第二个是为什么我只收到 CORS 错误的 70%
有时我的管理面板发出请求,如果我的 API 设置错误,那不应该发生,对吧?
我整天都在寻找解决方案,并尝试以各种可能的方式创建 corsOptions
,但我仍然遇到同样的问题,无论我做什么。
CORS 错误:
API源代码:
import cors from 'cors';
import express from 'express';
import jwt from 'jsonwebtoken';
import { generateToken, getCleanUser } from './utils';
import { Admins, Utenti, Prodotti, Acquisti } from './models';
require('dotenv').config();
const app = express();
const port = process.env.PORT;
const mongoose = require('mongoose');
mongoose.connect('mongodb://domain', {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
}).then(db => console.log('Il DB è connesso!'))
.catch(err => console.log(err));
// CORS
app.use(cors());
// parse application/json
app.use(express.json());
// parse application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));
// Middleware that checks if JWT token exists and verifies it if it does exist.
// In all future routes, this helps to know if the request is authenticated or not.
app.use((req, res, next) => {
// check header or url parameters or post parameters for token
let token = req.headers['authorization'];
if (!token) return next(); //if no token, continue
token = token.replace('Bearer ', '');
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
} else {
req.user = user; //set the user to req so other routes can use it
next();
}
});
});
// request handlers
app.get('/api', (req, res) => {
if (!req.user) return res.status(401).json({ success: false, message: 'Invalid user to access it.' });
res.send('Welcome! - ' + req.user.username);
});
//*================================
//* ADMINS SIGNIN
//*================================
app.post('/api/admins/signin', async (req, res) => {
try {
const user = req.body.username;
const pwd = req.body.password;
// return 400 status if username/password is not exist
if (!user || !pwd) {
return res.status(401).json({
error: true,
message: "Username or Password required!"
});
}
await Admins.findOne({ 'username': user, 'password': pwd }, (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the credential is not match.
if (!data) {
return res.status(401).json({
error: true,
message: "Username or Password is Wrong!"
});
}
// generate token
const token = generateToken(data);
// get basic user details
const userObj = getCleanUser(data);
// return the token along with user details
return res.json({ user: userObj, token });
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DI ADMIN SIGNIN >> ${error}`);
return res.status(400);
}
});
//*================================
//* USERS SIGNIN
//*================================
app.post('/api/users/signin', async (req, res) => {
try {
const user = req.body.username;
const pwd = req.body.password;
// return 400 status if username/password is not exist
if (!user || !pwd) {
return res.status(401).json({
error: true,
message: "Username or Password required!"
});
}
await Utenti.findOne({ 'username': user, 'password': pwd }, (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the credential is not match.
if (!data) {
return res.status(401).json({
error: true,
message: "Username or Password is Wrong!"
});
}
// generate token
const token = generateToken(data);
// get basic user details
const userObj = getCleanUser(data);
// return the token along with user details
return res.json({ user: userObj, token });
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DI USERS SIGNIN >> ${error}`);
return res.status(400);
}
});
//*================================
//* USERS SIGNUP
//*================================
app.post('/api/users/signup', async (req, res) => {
try {
// return 400 status if username/password is not exist
if (!req.body.username || !req.body.password || !req.body.email) {
return res.status(400).json({
error: true,
message: "Every field in the form is required!"
});
}
await Utenti.findOne({ 'username': req.body.username }, async (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
if (data) {
return res.status(400).json({
error: true,
message: "Username already taken!"
});
}
await Utenti.find().sort({ _id: -1 }).exec(async (err, lastUserSignedUp) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
let newUser;
if (lastUserSignedUp[0]) {
newUser = new Utenti({
id: (lastUserSignedUp[0].id + 1),
username: req.body.username,
password: req.body.password,
email: req.body.email
});
} else {
newUser = new Utenti({
id: 0,
username: req.body.username,
password: req.body.password,
email: req.body.email
});
}
await newUser.save();
return res.json(newUser);
});
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DI USERS SIGNUP >> ${error}`);
return res.status(401)
}
});
//*================================
//* ADMINS VERIFY THE TOKEN
//*================================
app.get('/api/verifyAdminToken', (req, res) => {
// check header or url parameters or post parameters for token
const token = req.body.token || req.query.token;
if (!token) {
return res.status(400).json({
error: true,
message: "Token is required."
});
}
// check token that was passed by decoding token using secret
jwt.verify(token, process.env.JWT_SECRET, async (err, user) => {
try {
if (err) return res.status(401).json({
error: true,
message: "Invalid token."
});
await Admins.findOne({ 'username': user.username, 'password': user.password }, (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the userId does not match.
if (user._id !== data._id.toString()) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
}
// get basic user details
const userObj = getCleanUser(data);
return res.json({ user: userObj, token });
});
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DI VERIFY-TOKEN >> ${error}`);
}
});
});
//*================================
//* USERS VERIFY THE TOKEN
//*================================
app.get('/api/verifyToken', (req, res) => {
// check header or url parameters or post parameters for token
const token = req.body.token || req.query.token;
if (!token) {
return res.status(400).json({
error: true,
message: "Token is required."
});
}
// check token that was passed by decoding token using secret
jwt.verify(token, process.env.JWT_SECRET, async (err, user) => {
try {
if (err) return res.status(401).json({
error: true,
message: "Invalid token."
});
await Utenti.findOne({ 'username': user.username, 'password': user.password }, (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the userId does not match.
if (user._id !== data._id.toString()) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
}
// get basic user details
const userObj = getCleanUser(data);
return res.json({ user: userObj, token });
});
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DI VERIFY-TOKEN >> ${error}`);
}
});
});
//*================================
//* PRODOTTI
//*================================
app.route('/api/prodotti')
.get(async (req, res) => {
try {
if (req.query.categoria !== undefined) {
if (req.query.categoria === 'all') {
await Prodotti.find().exec((err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
})
} else {
await Prodotti.find({ 'categoria': req.query.categoria }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
})
}
} else {
if (!req.query.id) {
await Prodotti.findOne({ 'nome': req.query.nome }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
if (req.query.desc === 'true' && data) {
return res.json(data.desc);
} else {
return res.json(data);
}
});
} else {
await Prodotti.findOne({ 'id': req.query.id }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
});
}
}
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DEI PRODOTTI >> ${error}`);
}
})
.post(async (req, res) => {
if (req.user) {
try {
await Admins.findOne({ 'username': req.user.username, 'password': req.user.password }, async (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the credential is not match.
if (!data) {
return res.status(401).json({
error: true,
message: "Access Denied"
});
}
await Prodotti.find().sort({ _id: -1 }).exec(async (err, lastProdottoAggiunto) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
let nuovoProdotto;
if (lastProdottoAggiunto[0]) {
nuovoProdotto = new Prodotti({
id: (lastProdottoAggiunto[0].id + 1),
nome: req.body.nome,
categoria: req.body.categoria,
prezzo: req.body.prezzo,
id_api: req.body.id_api,
desc: req.body.desc
});
} else {
nuovoProdotto = new Prodotti({
id: 0,
nome: req.body.nome,
categoria: req.body.categoria,
prezzo: req.body.prezzo,
id_api: req.body.id_api,
desc: req.body.desc
});
}
await nuovoProdotto.save();
return res.json(nuovoProdotto);
});
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DEI PRODOTTI >> ${error}`);
}
return res.status(403).json({
error: true,
message: 'Access Denied'
});
}
})
.delete(async (req, res) => {
try {
await Prodotti.findOneAndDelete({ 'id': req.body.id }, (err, removed) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json({ success: 'true' });
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DEI PRODOTTI >> ${error}`);
}
});
//*================================
//* ACQUISTI
//*================================
app.route('/api/acquisti')
.get(async (req, res) => {
try {
if (!req.query.id) {
await Acquisti.find({ 'id': req.query.id }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
});
}
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DEGLI ACQUISTI >> ${error}`);
}
})
.post(async (req, res) => {
if (req.user) {
try {
const nuovoAcquisto = new Acquisti({
id: orderId,
id: req.body.id,
categoria: req.body.categoria,
nome: req.body.nome,
link: req.body.link,
qty: req.body.qty,
spesa: req.body.spesa
});
await nuovoAcquisto.save();
return res.json(nuovoAcquisto);
} catch (error) {
return res.status(401).json({
error: true,
message: `ERRORE NELLA POST REQUEST DEGLI ACQUISTI >> ${error}`
});
}
} else {
return res.status(403).json({
error: true,
message: 'Access Denied'
});
}
});
//*================================
//* UTENTI
//*================================
app.route('/api/utenti')
.get(async (req, res) => {
if (req.user) {
try {
if (req.query.id) {
await Utenti.findOne({ 'id': req.query.id }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
});
} else {
await Utenti.find().exec((err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
})
}
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DEGLI UTENTI >> ${error}`);
}
} else {
return res.status(403).send(`
<div style="text-align: center; font-family: 'Trebuchet MS', sans-serif;">
</div>
`);
}
})
.delete(async (req, res) => {
try {
await Utenti.findOneAndDelete({ 'id': req.body.id }, (err, removed) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json({ success: 'true' });
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DEI PRODOTTI >> ${error}`);
}
});
app.listen(port, () => {
console.log('Porta API: ' + port);
});
您正在发出触发 pre-flight 的跨源请求(这可以从浏览器中记录的内容中看出)。这是一个额外的 COR 级别,可能由任何数量的事情引起,例如自定义 headers、content-type 超出一个小的允许集等......显然只有您的一些请求触发 pre-flight 这就是为什么其中一些可以正常工作而另一些则不能。您可以阅读 simple and pre-flighted 个请求,看看是什么导致浏览器决定它必须 pre-flight 个请求。
如果您查看 Chrome 调试器的网络选项卡,您将能够看到浏览器发出 OPTIONS 请求,并且可能返回 404 或未获得正确的 headers 返回这就是 pre-flight 请求失败并且浏览器随后拒绝 CORs 请求的原因。
要允许 pre-flighted CORs 请求,您的服务器必须以 2xx 状态和正确的 CORS headers.
响应 OPTIONS 请求
您将需要一个 app.options(...)
请求处理程序,它允许所有请求通过或仅允许某些请求通过返回正确的 CORS headers 并以 2xx 状态(通常为 204)响应。
由于您使用 cors
模块来帮助您,您可以阅读有关 pre-flight 使用该模块的请求 here。
问题是我的 nginx
配置和 Cloudflare 阻止了 COR headers。
这是新的工作 nginx 配置:
server {
listen 80;
listen [::]:80;
root /var/www/main-domain.tld;
index index.html;
server_name main-domain.tld www.main-domain.tld;
error_page 404 /404.html;
location = /404.html {
root /var/www/main-domain.tld;
internal;
}
error_page 400 401 403 503 /custom_50x.html;
location = /custom_50x.html {
root /usr/share/nginx/html;
internal;
}
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, HEAD';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, HEAD';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, HEAD';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
try_files $uri $uri/ =404;
if ($request_filename ~* ^.+.html$) {
break;
}
# add .html to URI and serve file, directory, or symlink if it exists
if (-e $request_filename.html) {
rewrite ^/(.*)$ /.html last;
break;
}
if (!-e $request_filename){
rewrite ^(.*)$ /index.html break;
}
}
location /api {
proxy_redirect off;
proxy_set_header host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-forward-for $proxy_add_x_forwarded_for;
proxy_pass http://localhost:api-port;
}
location ~ /\.ht {
deny all;
}
}
这是修复 Cloudflare 的方法。按照“添加或更改 CORS headers”的说明进行操作,并至少发送一次正确的 COR headers:
我有一个 Express API 托管在位于 main-domain.tld/api/
的 ngnix 上,还有一个位于 sub.main-domain.tld
的管理面板将请求发送到我的 API.
当我尝试从我的管理面板向我的 API 发送请求时,我收到 CORS 错误,70% 的时间与我请求的路由和使用的方法无关(POST、获取等)。
我不明白两件事:
- 首先是为什么我在启用所有功能后收到 CORS 错误 源自我的 API 源代码。
- 第二个是为什么我只收到 CORS 错误的 70% 有时我的管理面板发出请求,如果我的 API 设置错误,那不应该发生,对吧?
我整天都在寻找解决方案,并尝试以各种可能的方式创建 corsOptions
,但我仍然遇到同样的问题,无论我做什么。
CORS 错误:
API源代码:
import cors from 'cors';
import express from 'express';
import jwt from 'jsonwebtoken';
import { generateToken, getCleanUser } from './utils';
import { Admins, Utenti, Prodotti, Acquisti } from './models';
require('dotenv').config();
const app = express();
const port = process.env.PORT;
const mongoose = require('mongoose');
mongoose.connect('mongodb://domain', {
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
}).then(db => console.log('Il DB è connesso!'))
.catch(err => console.log(err));
// CORS
app.use(cors());
// parse application/json
app.use(express.json());
// parse application/x-www-form-urlencoded
app.use(express.urlencoded({ extended: true }));
// Middleware that checks if JWT token exists and verifies it if it does exist.
// In all future routes, this helps to know if the request is authenticated or not.
app.use((req, res, next) => {
// check header or url parameters or post parameters for token
let token = req.headers['authorization'];
if (!token) return next(); //if no token, continue
token = token.replace('Bearer ', '');
jwt.verify(token, process.env.JWT_SECRET, (err, user) => {
if (err) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
} else {
req.user = user; //set the user to req so other routes can use it
next();
}
});
});
// request handlers
app.get('/api', (req, res) => {
if (!req.user) return res.status(401).json({ success: false, message: 'Invalid user to access it.' });
res.send('Welcome! - ' + req.user.username);
});
//*================================
//* ADMINS SIGNIN
//*================================
app.post('/api/admins/signin', async (req, res) => {
try {
const user = req.body.username;
const pwd = req.body.password;
// return 400 status if username/password is not exist
if (!user || !pwd) {
return res.status(401).json({
error: true,
message: "Username or Password required!"
});
}
await Admins.findOne({ 'username': user, 'password': pwd }, (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the credential is not match.
if (!data) {
return res.status(401).json({
error: true,
message: "Username or Password is Wrong!"
});
}
// generate token
const token = generateToken(data);
// get basic user details
const userObj = getCleanUser(data);
// return the token along with user details
return res.json({ user: userObj, token });
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DI ADMIN SIGNIN >> ${error}`);
return res.status(400);
}
});
//*================================
//* USERS SIGNIN
//*================================
app.post('/api/users/signin', async (req, res) => {
try {
const user = req.body.username;
const pwd = req.body.password;
// return 400 status if username/password is not exist
if (!user || !pwd) {
return res.status(401).json({
error: true,
message: "Username or Password required!"
});
}
await Utenti.findOne({ 'username': user, 'password': pwd }, (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the credential is not match.
if (!data) {
return res.status(401).json({
error: true,
message: "Username or Password is Wrong!"
});
}
// generate token
const token = generateToken(data);
// get basic user details
const userObj = getCleanUser(data);
// return the token along with user details
return res.json({ user: userObj, token });
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DI USERS SIGNIN >> ${error}`);
return res.status(400);
}
});
//*================================
//* USERS SIGNUP
//*================================
app.post('/api/users/signup', async (req, res) => {
try {
// return 400 status if username/password is not exist
if (!req.body.username || !req.body.password || !req.body.email) {
return res.status(400).json({
error: true,
message: "Every field in the form is required!"
});
}
await Utenti.findOne({ 'username': req.body.username }, async (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
if (data) {
return res.status(400).json({
error: true,
message: "Username already taken!"
});
}
await Utenti.find().sort({ _id: -1 }).exec(async (err, lastUserSignedUp) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
let newUser;
if (lastUserSignedUp[0]) {
newUser = new Utenti({
id: (lastUserSignedUp[0].id + 1),
username: req.body.username,
password: req.body.password,
email: req.body.email
});
} else {
newUser = new Utenti({
id: 0,
username: req.body.username,
password: req.body.password,
email: req.body.email
});
}
await newUser.save();
return res.json(newUser);
});
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DI USERS SIGNUP >> ${error}`);
return res.status(401)
}
});
//*================================
//* ADMINS VERIFY THE TOKEN
//*================================
app.get('/api/verifyAdminToken', (req, res) => {
// check header or url parameters or post parameters for token
const token = req.body.token || req.query.token;
if (!token) {
return res.status(400).json({
error: true,
message: "Token is required."
});
}
// check token that was passed by decoding token using secret
jwt.verify(token, process.env.JWT_SECRET, async (err, user) => {
try {
if (err) return res.status(401).json({
error: true,
message: "Invalid token."
});
await Admins.findOne({ 'username': user.username, 'password': user.password }, (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the userId does not match.
if (user._id !== data._id.toString()) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
}
// get basic user details
const userObj = getCleanUser(data);
return res.json({ user: userObj, token });
});
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DI VERIFY-TOKEN >> ${error}`);
}
});
});
//*================================
//* USERS VERIFY THE TOKEN
//*================================
app.get('/api/verifyToken', (req, res) => {
// check header or url parameters or post parameters for token
const token = req.body.token || req.query.token;
if (!token) {
return res.status(400).json({
error: true,
message: "Token is required."
});
}
// check token that was passed by decoding token using secret
jwt.verify(token, process.env.JWT_SECRET, async (err, user) => {
try {
if (err) return res.status(401).json({
error: true,
message: "Invalid token."
});
await Utenti.findOne({ 'username': user.username, 'password': user.password }, (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the userId does not match.
if (user._id !== data._id.toString()) {
return res.status(401).json({
error: true,
message: "Invalid user."
});
}
// get basic user details
const userObj = getCleanUser(data);
return res.json({ user: userObj, token });
});
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DI VERIFY-TOKEN >> ${error}`);
}
});
});
//*================================
//* PRODOTTI
//*================================
app.route('/api/prodotti')
.get(async (req, res) => {
try {
if (req.query.categoria !== undefined) {
if (req.query.categoria === 'all') {
await Prodotti.find().exec((err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
})
} else {
await Prodotti.find({ 'categoria': req.query.categoria }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
})
}
} else {
if (!req.query.id) {
await Prodotti.findOne({ 'nome': req.query.nome }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
if (req.query.desc === 'true' && data) {
return res.json(data.desc);
} else {
return res.json(data);
}
});
} else {
await Prodotti.findOne({ 'id': req.query.id }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
});
}
}
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DEI PRODOTTI >> ${error}`);
}
})
.post(async (req, res) => {
if (req.user) {
try {
await Admins.findOne({ 'username': req.user.username, 'password': req.user.password }, async (err, data) => {
if (err) {
console.error('DB ERROR => ', err);
}
// return 401 status if the credential is not match.
if (!data) {
return res.status(401).json({
error: true,
message: "Access Denied"
});
}
await Prodotti.find().sort({ _id: -1 }).exec(async (err, lastProdottoAggiunto) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
let nuovoProdotto;
if (lastProdottoAggiunto[0]) {
nuovoProdotto = new Prodotti({
id: (lastProdottoAggiunto[0].id + 1),
nome: req.body.nome,
categoria: req.body.categoria,
prezzo: req.body.prezzo,
id_api: req.body.id_api,
desc: req.body.desc
});
} else {
nuovoProdotto = new Prodotti({
id: 0,
nome: req.body.nome,
categoria: req.body.categoria,
prezzo: req.body.prezzo,
id_api: req.body.id_api,
desc: req.body.desc
});
}
await nuovoProdotto.save();
return res.json(nuovoProdotto);
});
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DEI PRODOTTI >> ${error}`);
}
return res.status(403).json({
error: true,
message: 'Access Denied'
});
}
})
.delete(async (req, res) => {
try {
await Prodotti.findOneAndDelete({ 'id': req.body.id }, (err, removed) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json({ success: 'true' });
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DEI PRODOTTI >> ${error}`);
}
});
//*================================
//* ACQUISTI
//*================================
app.route('/api/acquisti')
.get(async (req, res) => {
try {
if (!req.query.id) {
await Acquisti.find({ 'id': req.query.id }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
});
}
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DEGLI ACQUISTI >> ${error}`);
}
})
.post(async (req, res) => {
if (req.user) {
try {
const nuovoAcquisto = new Acquisti({
id: orderId,
id: req.body.id,
categoria: req.body.categoria,
nome: req.body.nome,
link: req.body.link,
qty: req.body.qty,
spesa: req.body.spesa
});
await nuovoAcquisto.save();
return res.json(nuovoAcquisto);
} catch (error) {
return res.status(401).json({
error: true,
message: `ERRORE NELLA POST REQUEST DEGLI ACQUISTI >> ${error}`
});
}
} else {
return res.status(403).json({
error: true,
message: 'Access Denied'
});
}
});
//*================================
//* UTENTI
//*================================
app.route('/api/utenti')
.get(async (req, res) => {
if (req.user) {
try {
if (req.query.id) {
await Utenti.findOne({ 'id': req.query.id }, (err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
});
} else {
await Utenti.find().exec((err, data) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json(data);
})
}
} catch (error) {
console.log(`ERRORE NELLA GET REQUEST DEGLI UTENTI >> ${error}`);
}
} else {
return res.status(403).send(`
<div style="text-align: center; font-family: 'Trebuchet MS', sans-serif;">
</div>
`);
}
})
.delete(async (req, res) => {
try {
await Utenti.findOneAndDelete({ 'id': req.body.id }, (err, removed) => {
if (err) return res.status(401).json({
error: true,
message: 'DB Problem... '
});
return res.json({ success: 'true' });
});
} catch (error) {
console.log(`ERRORE NELLA POST REQUEST DEI PRODOTTI >> ${error}`);
}
});
app.listen(port, () => {
console.log('Porta API: ' + port);
});
您正在发出触发 pre-flight 的跨源请求(这可以从浏览器中记录的内容中看出)。这是一个额外的 COR 级别,可能由任何数量的事情引起,例如自定义 headers、content-type 超出一个小的允许集等......显然只有您的一些请求触发 pre-flight 这就是为什么其中一些可以正常工作而另一些则不能。您可以阅读 simple and pre-flighted 个请求,看看是什么导致浏览器决定它必须 pre-flight 个请求。
如果您查看 Chrome 调试器的网络选项卡,您将能够看到浏览器发出 OPTIONS 请求,并且可能返回 404 或未获得正确的 headers 返回这就是 pre-flight 请求失败并且浏览器随后拒绝 CORs 请求的原因。
要允许 pre-flighted CORs 请求,您的服务器必须以 2xx 状态和正确的 CORS headers.
响应 OPTIONS 请求您将需要一个 app.options(...)
请求处理程序,它允许所有请求通过或仅允许某些请求通过返回正确的 CORS headers 并以 2xx 状态(通常为 204)响应。
由于您使用 cors
模块来帮助您,您可以阅读有关 pre-flight 使用该模块的请求 here。
问题是我的 nginx
配置和 Cloudflare 阻止了 COR headers。
这是新的工作 nginx 配置:
server {
listen 80;
listen [::]:80;
root /var/www/main-domain.tld;
index index.html;
server_name main-domain.tld www.main-domain.tld;
error_page 404 /404.html;
location = /404.html {
root /var/www/main-domain.tld;
internal;
}
error_page 400 401 403 503 /custom_50x.html;
location = /custom_50x.html {
root /usr/share/nginx/html;
internal;
}
location / {
if ($request_method = 'OPTIONS') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, HEAD';
#
# Custom headers and headers various browsers *should* be OK with but aren't
#
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
#
# Tell client that this pre-flight info is valid for 20 days
#
add_header 'Access-Control-Max-Age' 1728000;
add_header 'Content-Type' 'text/plain; charset=utf-8';
add_header 'Content-Length' 0;
return 204;
}
if ($request_method = 'POST') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, HEAD';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
if ($request_method = 'GET') {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE, HEAD';
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
}
try_files $uri $uri/ =404;
if ($request_filename ~* ^.+.html$) {
break;
}
# add .html to URI and serve file, directory, or symlink if it exists
if (-e $request_filename.html) {
rewrite ^/(.*)$ /.html last;
break;
}
if (!-e $request_filename){
rewrite ^(.*)$ /index.html break;
}
}
location /api {
proxy_redirect off;
proxy_set_header host $host;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-forward-for $proxy_add_x_forwarded_for;
proxy_pass http://localhost:api-port;
}
location ~ /\.ht {
deny all;
}
}
这是修复 Cloudflare 的方法。按照“添加或更改 CORS headers”的说明进行操作,并至少发送一次正确的 COR headers: