Javascript 选项请求不一致(在部署中)? 介绍
因此,我正在使用MERN堆栈(与Heroku+Netlify一起使用),并且在处理删除请求时遇到了一些非常奇怪的一致性问题。在过去的几年里,我尝试了无数的解决方案 三天来,我一直在努力让这一切顺利进行,但都没有成功。这些解决方案中有很多都是有效的 来自stack overflow,所以如果你想让我转到另一个帖子,我可能已经看到了。我已经搜索了网络的每一个部分,写这篇文章是我最后的选择 问题 因此,当我发出一个删除请求时,我得到的是每个常用选项请求,因为我在请求的自定义头中发送了一个令牌(“x-auth-token”)。选项请求总是以204来解析,这意味着一切都应该正常。然而,之后,并没有像应该的那个样的删除请求。这在本质上是我的问题。我检查了我的Heroku日志,只看到选项请求,没有其他内容 矛盾? 这就是我一直很困惑的地方。问题是,有时候它确实有效。我在API中使用的其他路由(如登录和创建新帖子)也可以工作,尽管我使用的是相同的中间件。 每次它工作时,我都会收到OPTIONS请求,然后是DELETE请求(状态为200),就像我预期的那样 如果您想要一个可重新创建的场景示例: 在登录并获得有效令牌后,我创建了X个数字的帖子,然后我可以在主页上的帖子列表中看到这些帖子呈现。然后我浏览其中一篇文章,然后单击确认按钮将其删除。我会自动被重定向到列表中的下一篇文章。我重复这个直到我到达最后一站。我删除了那个帖子,因为已经没有帖子了,我被重定向到了帖子列表,它是。。。不是空的!我尝试删除的最后一篇帖子仍然存在 请记住,所有的删除请求都是以完全相同的方式发送的,因此我非常确定这不是前端问题,因此无需在代码中进行修改。我已经记录了所有内容并进行了调试,它与我预期的完全一致 (create post不会重定向,而delete post会重定向?我看不出这会对任何事情产生什么影响,因为delete请求会按常规发送……尽管可能有一个解决方案就在这个事实中。) 我尝试过的解决方案 科尔斯 首先,你可能已经冲到键盘前告诉我这是一个CORS问题。我昨天也这么想,但现在不太确定。我尝试过在CORS中搞乱所有可能的配置设置,以使其正常工作。因为我的两个网站位于不同的域上,所以CORS会验证请求。我已经将我的前端网站添加到了白名单中,所有其他请求都正常通过,所以没有问题。我尝试在配置中添加Alloweaders选项,但除了默认设置之外,它没有做任何事情。我还向配置中允许的方法添加了“选项”,但仍然没有。我还使用app.use(cors({config}))。稍后我将包含一些代码,以详细了解其中的一些内容 调试 我基本上通过在所有地方插入console.logs进行了测试,发现当options请求没有导致DELETE请求时,中间件、options路由(我尝试使用相同的路由url创建一个options路由)或原始post路由都不会被执行 静态服务器 这可能是我的一些经验不足之处(这是我的第一个网络项目)。我看到一些解决方案告诉我们需要一个静态服务器。所以我尝试设置一个静态服务器,但没有看到任何结果。所以我不太确定这是怎么实现的 异步并等待 此时我只是在尝试,所以我将所有路由设置为异步,以查看它是否有任何作用。没有 其他 我还搞乱了环境变量和dotenv,以及其他我记不起来的东西。我认为这里的一切应该已经足够了解情况了 代码 index.jsJavascript 选项请求不一致(在部署中)? 介绍,javascript,node.js,reactjs,express,axios,Javascript,Node.js,Reactjs,Express,Axios,因此,我正在使用MERN堆栈(与Heroku+Netlify一起使用),并且在处理删除请求时遇到了一些非常奇怪的一致性问题。在过去的几年里,我尝试了无数的解决方案 三天来,我一直在努力让这一切顺利进行,但都没有成功。这些解决方案中有很多都是有效的 来自stack overflow,所以如果你想让我转到另一个帖子,我可能已经看到了。我已经搜索了网络的每一个部分,写这篇文章是我最后的选择 问题 因此,当我发出一个删除请求时,我得到的是每个常用选项请求,因为我在请求的自定义头中发送了一个令牌(“x-a
const express = require('express');
require("dotenv").config({ path: "variables.env" });
const mongoose = require('mongoose');
const bodyParser = require('body-parser');
const routes = require("./routes/router");
const cors = require("cors");
const morgan = require('morgan')
const app = express();
const whitelist = [
process.env.ORIGIN
];
app.use(
cors({
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
console.log(origin);
callback(new Error("Not allowed by CORS"));
}
}, //frontend server localhost:3000
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
credentials: true, // enable set cookie
}));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(morgan('dev'));
mongoose.connect(process.env.MONGODB_URL, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
});
const db = mongoose.connection;
db.on('error', console.error.bind(console, 'connection error:'));
db.once('open', () => {
console.log('connected to db');
});
const userSchema = mongoose.Schema({
name: String,
password: String
});
// Routes
// TODO: make seperate routers/routes
app.use("/", routes);
// Serve static assets if in production
if (process.env.NODE_ENV === 'production') {
// Set static folder
app.use(express.static('client/build'));
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
}
// TODO: set up custom port in future
app.listen(process.env.PORT, () => console.log(`Server listening at http://localhost:${process.env.PORT}`));
// Callback functions?
路由器.js
const express = require('express');
const router = express.Router();
const Post = require('../models/Post');
const User = require('../models/User');
const bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const auth = require('../middleware/auth');
const adminAuth = require('../middleware/adminAuth');
const cors = require("cors");
require("dotenv").config({ path: "variables.env" });
// import 'moment'
// second onwards are handlers => triggers like the post body then next() to go to the next handler
router.post('/api/add_post', adminAuth, async (req, res, next) => {
try{
newPost = new Post({
title: req.body.title,
body: req.body.body,
author: req.body.author,
created: req.body.created,
});
const savedPost = await newPost.save();
if (!savedUser) throw Error('Something went wrong saving the post');
res.send(savedPost);
} catch (e) {
res.status(400).json({ msg: e.message });
}
});
router.delete('/api/delete_post/:id', adminAuth, async (req, res, next) => {
// timeout?
// console.log(req.body);
try{
const id = req.params.id;
if(!id) throw Error('Invalid ID');
const post = await Post.findById(id);
if (!post) throw Error('Post doesn\'t exist');
const removed = await post.remove();
if(!removed) throw Error('Problem with deleting the post');
res.status(200).json({ success: true });
} catch(e) {
console.log("Error: ", e.message);
res.status(400).json({ msg: e.message, success: false });
}
});
// TODO : UPDATE for async soon
router.post('/api/update_post', adminAuth, async (req, res, next) => {
const id = req.body._id;
test_post_data = {
title: req.body.title,
body: req.body.body,
author: req.body.author,
modified: req.body.modified,
};
console.log(test_post_data, id);
Post.updateOne({ _id: id }, test_post_data, (err) => {
if(err) return next(err);
return res.status(200);
});
});
router.get('/api/get_posts', async (req, res, next) => {
try{
const posts = await Post.find();
if(!posts) throw Error('Error with fetching the posts')
res.send(posts.reverse());
} catch (e) {
res.status(400).json({ msg: e.message });
}
});
router.get('/api/get_chapter/:id', async (req, res, next) => {
try{
const id = req.params.id;
const post = await Post.findOne({_id: id})
if(!post) throw Error('No post was found')
res.send(post);
} catch(e) {
res.status(400).json({ msg: e.message })
}
});
// User routes
// TODO : make in seperate file
router.post('/api/user/register', async (req, res) => {
const { name, email, password } = req.body;
// Simple validation
if (!name || !email || !password) {
return res.status(400).json({ msg: 'Please enter all fields' });
}
try {
const user = await User.findOne({ email });
if (user) throw Error('User already exists');
const salt = await bcrypt.genSalt(10);
if (!salt) throw Error('Something went wrong with bcrypt');
const hash = await bcrypt.hash(password, salt);
if (!hash) throw Error('Something went wrong hashing the password');
const newUser = new User({
name,
email,
password: hash,
admin: false
});
const savedUser = await newUser.save();
if (!savedUser) throw Error('Something went wrong saving the user');
// TODO : check up on expires stuff : 3600 = 1 hr
const token = jwt.sign({ id: savedUser._id, admin: savedUser.admin }, process.env.JWT_SECRET, {
expiresIn: 3600
});
res.status(200).json({
token,
user: {
id: savedUser.id,
name: savedUser.name,
email: savedUser.email,
admin: savedUser.admin
}
});
} catch (e) {
res.status(400).json({ error: e.message });
}
});
router.post('/api/user/login', async (req, res) => {
const { name, password } = req.body;
// Simple validation
if (!name || !password) {
return res.status(400).json({ msg: 'Please enter all fields' });
}
try {
// Check for existing user
const user = await User.findOne({ name });
if (!user) throw Error('User Does not exist');
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) throw Error('Invalid credentials');
const token = jwt.sign({ id: user._id, admin: user.admin }, process.env.JWT_SECRET, { expiresIn: 3600 });
if (!token) throw Error('Couldnt sign the token');
res.status(200).json({
token,
user: {
id: user._id,
name: user.name,
email: user.email,
admin: user.admin
}
});
} catch (e) {
res.status(400).json({ msg: e.message });
}
});
module.exports = router;
adminAuth.js
const jwt = require('jsonwebtoken')
require("dotenv").config({ path: "variables.env" });
module.exports = (req, res, next) => {
console.log(req.header('x-auth-token'));
const token = req.header('x-auth-token');
// Check for token
if (!token)
return res.status(401).json({ msg: 'No token, authorizaton denied' });
try {
// Verify token
const decoded = jwt.verify(token, process.env.JWT_SECRET);
console.log('decoded:', decoded);
if(!decoded.admin)
return res.status(401).json({ msg: 'Not an admin, authorization denied' });
// Add user from payload
// console.log('decoded:', decoded);
req.user = decoded;
next();
} catch (e) {
res.status(400).json({ msg: 'Token is not valid' });
}
};
链接以获取请求示例和Heroku日志,因为Stackoverflow说这是垃圾邮件:
编辑
我将Chrome请求和响应标题粘贴到底部的gist中,但是没有响应数据
我已经调试了一点,用它来检查差异,我发现当delete操作结束时,red(cancelled)请求有头,而非working请求则完全为空(如果这意味着什么的话,则用“临时头”填充)
我无法将请求标题复制粘贴到工作红色(已取消)标题的要点中。但是,我粘贴了所有我认为可能对chrome有用的东西,希望它能有所帮助
另外,我在使用Chrome网络工具时没有看到任何删除请求,我在另一个工具上看到了它们。不确定这是否重要,可能只是某个配置选项。所以,我还没有找到确切的答案,但我找到了解决办法 事实证明,这可能与axios有关,在过去的3天里,我一直在寻找错误的东西 这条线帮助我: 我在用于删除按钮的onClick方法中添加了一个
e.preventDefault()
。
这修复了问题,但没有重定向(我使用
href={link}
),因此我将为react router添加一个条件呈现来重定向页面。我不知道有更好的方法,所以也许能给我一些想法。如果我有进一步的问题,我会编辑。因此,我还没有找到确切的答案,但我找到了解决办法
事实证明,这可能与axios有关,在过去的3天里,我一直在寻找错误的东西
这条线帮助我:
我在onClic中添加了一个e.preventDefault()