由于 "CORS preflight request",NodeJS API 创建了两个会话
NodeJS API creates two sessions because of "CORS preflight request"
我目前正在用 NodeJS 开发一个 API,在 VueJS 中开发一个 WebClient。
我想创建一个简单的 login/logout 机制。 Webclient 应该将请求发送到 API 并且 API 应该处理不同用户的 sessions 并从其 mongoDB.
提供数据
最近遇到一个奇怪的问题。当我想通过 WebClient 登录时,浏览器显示它向 API 发送 两个不同的 headers。一个“OPTIONS”header 和一个“POST”header。 POST header 是由于我的 POST-Request (WebClient) 发送的,很清楚。由于 Mozillas 解释,我也理解 OPTION header 部分,因为浏览器想知道 API 的 CORS-configuration 是否已针对 WebClient 配置(或类似这样的东西)。
但是现在的问题是:
由于两个不同的 header-methods,我的 API 创建了两个 session-IDs 只有一个 login-post 操作(通过 WebClient),而这两个 session 之一与 WebClient 分离,不必要地消耗有价值的 space。这仅通过 WebClient 发生。使用 PostMan 不会显示此行为,只会创建一个 session,因为只发送一个 header。
我想知道的是:
既然发送 OPTIONS-header 是有原因的,我想知道如何防止我的 API 通过 WebClient 创建第二个 session。
由于这个问题是在测试我的 WebClient 后发生的,我很清楚 WebClient 没有配置或编写不正确,但我不知道哪里或如何 来防止这种情况,因为这个级别的 WebDev 对我来说是新的。比如:我必须配置我的 WebClient 还是 API?
如果需要更多代码,请告诉我您需要什么,我将编辑此 post 并附上所需代码。
//////////////////代码:
//// API:
// src/main.js:
const corsOptions = {
origin: "http://localhost:8080",
credentials:true,
methods: "GET,HEAD,POST",
preflightContinue: false,
optionsSuccessStatus: 204
};
// src/routes/LoginRoute.js:
router.post("/login", function(req,res,next){
console.log("// Routes/Login");
if(!req.user){
console.log("---- Info: User is not logged in");
passport.authenticate("local", (err, user, info) => {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({success:false,errors:["User not found"]});
}
req.login(user, (err) => {
if(err){
return next(err);
}
console.log("---- Info: Routing success");
return res.status(200).json({success:true});
});
})(req, res, next);
}else{
console.log("---- Info: User is already logged in");
return res.status(403).json({success:false,errors:["Already logged in"]});
}
});
//// VueJS
// src/store/index.js
actions:{
authenticate({commit},formData){
console.log("---- Info: Vuex/Store/Action/Authenticate - Trying to log in");
var url = "http://localhost:3000/api/login";
console.log(formData);
return Vue.axios.post(url,formData)
.then((res)=>{
console.log("---- Info: Vuex/Store/Action/Authenticate - Success");
commit('login',res.data);
return res.data;
})
.catch((err)=>{
console.log("---- Error: Vuex/Store/Action/Authenticate");
console.log(err);
// commit('logout');
return err;
});
}
}
////////////////// FireFox 网络分析:
我相信您显然使用的 cors 包可以解决这个问题。
在任何情况下,这都不是您前端的问题,它由您的后端处理,浏览器通常会产生 Postman 不存在的问题。 Postman 的构建是为了不关心浏览器的 CORS 问题。但是,您可以在 Postman 中设置 session 进行测试:https://blog.postman.com/sessions-faq/
回到问题:一种方法是对所有或特定路由使用中间件功能来过滤掉已经包含 session.
的请求
app.use((req, res, next) => {
if (req.session) {
// bypass new session creation, re-route or other solution
}
next()
})
另一种更灵活的方法是直接针对 OPTIONS header。我使用专门针对 OPTIONS header 的请求处理程序解决了无服务器代理功能中的类似问题。它过滤掉这样的请求,returns 一个“OK 信号”和慷慨的 headers 告诉浏览器它可以继续处理真正的请求,POST。
您可以尝试像这样的东西作为通用中间件,或将其添加为对某些端点的响应(代码未测试,只是在此处随意使用 Express 语法):
const optionsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
}
exports.reqHandler = async(req, res) => {
if (req.method === 'OPTIONS') {
return {
res.set(optionsHeaders)
res.status(200)
}
}
req.session.user = {}
req.session.user.id = uuid.v4()
// etc. ...
return res.status(200).json({
success: true,
data: req.session.user
msg: 'Session ID set'
})
}
所以我想出了如何防止浏览器向 API 服务器发送两个 header。
我必须配置 axios.post() 给函数一个 header 选项:
const axiosHeaders = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
Vue.axios.post(url,QueryString.stringify({username:username}),axiosHeaders)
.then(..)
[...]
将 "Configure-Type" 设置为 "application/x-www-form-urlencoded" 即可,但 form-data 必须用 QueryString.stringify(..) 函数包装。
有了这个,浏览器停止发送多个 header 和一个 post-request,在我的例子中,它停止在我的 API.[=11= 上创建多个会话]
我希望这对其他人也有用。
我目前正在用 NodeJS 开发一个 API,在 VueJS 中开发一个 WebClient。 我想创建一个简单的 login/logout 机制。 Webclient 应该将请求发送到 API 并且 API 应该处理不同用户的 sessions 并从其 mongoDB.
提供数据最近遇到一个奇怪的问题。当我想通过 WebClient 登录时,浏览器显示它向 API 发送 两个不同的 headers。一个“OPTIONS”header 和一个“POST”header。 POST header 是由于我的 POST-Request (WebClient) 发送的,很清楚。由于 Mozillas 解释,我也理解 OPTION header 部分,因为浏览器想知道 API 的 CORS-configuration 是否已针对 WebClient 配置(或类似这样的东西)。
但是现在的问题是:
由于两个不同的 header-methods,我的 API 创建了两个 session-IDs 只有一个 login-post 操作(通过 WebClient),而这两个 session 之一与 WebClient 分离,不必要地消耗有价值的 space。这仅通过 WebClient 发生。使用 PostMan 不会显示此行为,只会创建一个 session,因为只发送一个 header。
我想知道的是:
既然发送 OPTIONS-header 是有原因的,我想知道如何防止我的 API 通过 WebClient 创建第二个 session。
由于这个问题是在测试我的 WebClient 后发生的,我很清楚 WebClient 没有配置或编写不正确,但我不知道哪里或如何 来防止这种情况,因为这个级别的 WebDev 对我来说是新的。比如:我必须配置我的 WebClient 还是 API?
如果需要更多代码,请告诉我您需要什么,我将编辑此 post 并附上所需代码。
//////////////////代码:
//// API:
// src/main.js:
const corsOptions = {
origin: "http://localhost:8080",
credentials:true,
methods: "GET,HEAD,POST",
preflightContinue: false,
optionsSuccessStatus: 204
};
// src/routes/LoginRoute.js:
router.post("/login", function(req,res,next){
console.log("// Routes/Login");
if(!req.user){
console.log("---- Info: User is not logged in");
passport.authenticate("local", (err, user, info) => {
if (err) {
return next(err);
}
if (!user) {
return res.status(401).json({success:false,errors:["User not found"]});
}
req.login(user, (err) => {
if(err){
return next(err);
}
console.log("---- Info: Routing success");
return res.status(200).json({success:true});
});
})(req, res, next);
}else{
console.log("---- Info: User is already logged in");
return res.status(403).json({success:false,errors:["Already logged in"]});
}
});
//// VueJS
// src/store/index.js
actions:{
authenticate({commit},formData){
console.log("---- Info: Vuex/Store/Action/Authenticate - Trying to log in");
var url = "http://localhost:3000/api/login";
console.log(formData);
return Vue.axios.post(url,formData)
.then((res)=>{
console.log("---- Info: Vuex/Store/Action/Authenticate - Success");
commit('login',res.data);
return res.data;
})
.catch((err)=>{
console.log("---- Error: Vuex/Store/Action/Authenticate");
console.log(err);
// commit('logout');
return err;
});
}
}
////////////////// FireFox 网络分析:
我相信您显然使用的 cors 包可以解决这个问题。
在任何情况下,这都不是您前端的问题,它由您的后端处理,浏览器通常会产生 Postman 不存在的问题。 Postman 的构建是为了不关心浏览器的 CORS 问题。但是,您可以在 Postman 中设置 session 进行测试:https://blog.postman.com/sessions-faq/
回到问题:一种方法是对所有或特定路由使用中间件功能来过滤掉已经包含 session.
的请求 app.use((req, res, next) => {
if (req.session) {
// bypass new session creation, re-route or other solution
}
next()
})
另一种更灵活的方法是直接针对 OPTIONS header。我使用专门针对 OPTIONS header 的请求处理程序解决了无服务器代理功能中的类似问题。它过滤掉这样的请求,returns 一个“OK 信号”和慷慨的 headers 告诉浏览器它可以继续处理真正的请求,POST。
您可以尝试像这样的东西作为通用中间件,或将其添加为对某些端点的响应(代码未测试,只是在此处随意使用 Express 语法):
const optionsHeaders = {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Headers': 'Content-Type'
}
exports.reqHandler = async(req, res) => {
if (req.method === 'OPTIONS') {
return {
res.set(optionsHeaders)
res.status(200)
}
}
req.session.user = {}
req.session.user.id = uuid.v4()
// etc. ...
return res.status(200).json({
success: true,
data: req.session.user
msg: 'Session ID set'
})
}
所以我想出了如何防止浏览器向 API 服务器发送两个 header。
我必须配置 axios.post() 给函数一个 header 选项:
const axiosHeaders = {
headers: {
'Content-Type': 'application/x-www-form-urlencoded'
}
};
Vue.axios.post(url,QueryString.stringify({username:username}),axiosHeaders)
.then(..)
[...]
将 "Configure-Type" 设置为 "application/x-www-form-urlencoded" 即可,但 form-data 必须用 QueryString.stringify(..) 函数包装。
有了这个,浏览器停止发送多个 header 和一个 post-request,在我的例子中,它停止在我的 API.[=11= 上创建多个会话]
我希望这对其他人也有用。