我正在尝试创建一个登录/注册程序,用户在继续继续之前必须确认他们的电子邮件,尽管我收到了确认邮件&一切正常,但我的控制台中也出现了以下错误:
Cannot set headers after they are sent to the client
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at ServerResponse.setHeader (_http_outgoing.js:561:11)
at ServerResponse.header (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\response.js:771:10)
at ServerResponse.send (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\response.js:170:12)
at ServerResponse.json (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\response.js:267:15)
at errorHandler (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\server\error\errorHandler.js:20:39)
at Layer.handle_error (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\router\layer.js:71:5)
at trim_prefix (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\router\index.js:315:13)
at C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\router\index.js:284:7
at Function.process_params (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\router\index.js:335:12)
at next (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\router\index.js:275:10)
at C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\router\index.js:635:15
at next (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\router\index.js:260:14)
at next (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\node_modules\express\lib\router\route.js:127:14)
at exports.login (C:\Users\Administrator\Documents\Web Dev\Portfolio\FullStack\complete-auth\server\controllers\authControllers.js:131:5)我正在从我的登录控制器发送这封电子邮件,当isVerify=false这里是代码:
模型
const crypto = require("crypto");
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: [true, "Please enter your username"],
},
email: {
type: String,
required: [true, "Please enter your email"],
unique: true,
lowercase: true,
},
password: {
type: String,
required: [true, "Please enter a valid password"],
minlength: 8,
},
isAdmin: {
type: Boolean,
required: true,
default: false,
},
isVerified: {
type: Boolean,
required: true,
default: false,
},
resetPasswordToken: String,
resetPasswordExpired: Date,
verifyEmailToken: String,
verifyEmailExpired: Date,
});
// Hashing Password
UserSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
next();
}
try {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
next();
} catch (error) {
next(error);
}
});
// Checking if password entered is correct or not
UserSchema.methods.matchPasswords = async function (password) {
return await bcrypt.compare(password, this.password);
};
// Converting user data into JSON WEB TOKEN
UserSchema.methods.getSignedJwtAccessToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_ACCESS_SECRET, {
expiresIn: process.env.JWT_ACCESS_EXPIRE,
});
};
UserSchema.methods.getSignedJwtRefreshToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_REFRESH_SECRET, {
expiresIn: process.env.JWT_REFRESH_EXPIRE,
});
};
UserSchema.methods.getResetPasswordToken = function () {
const resetToken = crypto.randomBytes(20).toString("hex");
// Hash token (private key) and save to database
this.resetPasswordToken = crypto
.createHash("sha256")
.update(resetToken)
.digest("hex");
this.resetPasswordExpired = Date.now() + 10 * (60 * 1000); // Ten Minutes
return resetToken;
};
UserSchema.methods.getVerifyEmailToken = function () {
const confirmToken = crypto.randomBytes(20).toString("hex");
// Hash token (private key) and save to database
this.verifyEmailToken = crypto
.createHash("sha256")
.update(confirmToken)
.digest("hex");
this.verifyEmailExpired = Date.now() + 10 * (60 * 1000); // Ten Minutes
return confirmToken;
};
const User = mongoose.model("User", UserSchema);
module.exports = User;loginController
// @description: Login
// @route: POST /api/login
// @access: Public
exports.login = async (req, res, next) => {
const { email, password } = req.body;
if (!email || !password) {
return next(new ErrorResponse("Please enter credentials properly", 400));
}
try {
const user = await User.findOne({ email }).select("+password");
if (!user) {
return next(new ErrorResponse("Email not registered", 401));
}
const isMatch = await user.matchPasswords(password);
if (!isMatch) {
return next(new ErrorResponse("Invalid Password", 401));
}
// Sending Email if not Verified
if (!user.isVerified) {
try {
const confirmToken = user.getVerifyEmailToken();
await user.save();
const confirmUrl = `http://localhost:3000/confirmation/${confirmToken}`;
console.log("confirmURL: ", confirmUrl);
const html = `
<h1>VERIFY YOUR EMAIL</h1>
<p>Please verify your Email by clicking on the following link:</p>
<a href=${confirmUrl} clicktracking=off>${confirmUrl}</a>
`;
const message = `Verify your Email. Click on the fllowing link: ${confirmUrl}`;
try {
await sendEmail({
to: user.email,
subject: "VERIFICATION MAIL",
text: message,
html: html,
});
res.status(200).json({
success: true,
data: "A verification mail is send to your email. Please confirm before login",
});
} catch (err) {
user.verifyEmailToken = undefined;
user.verifyEmailExpired = undefined;
await user.save();
console.log("E^: ", err);
next(new ErrorResponse("Email could not be sent", 500));
}
} catch (error) {
next(error);
}
}
sendToken(user, 200, res);
} catch (error) {
next(error);
}
};
const sendToken = (user, statusCode, res) => {
const accessToken = user.getSignedJwtAccessToken();
const refreshToken = user.getSignedJwtRefreshToken();
refreshTokens.push(refreshToken);
res
.status(statusCode)
.cookie("accessToken", accessToken, {
expires: new Date(new Date().getTime() + 30 * 1000),
sameSite: "strict",
httpOnly: true,
}) // Dummie Cookie
.cookie("authSession", true, {
expires: new Date(new Date().getTime() + 30 * 1000),
})
.cookie("refreshToken", refreshToken, {
expires: new Date(new Date().getTime() + 31557600000),
sameSite: "strict",
httpOnly: true,
})
.cookie("refreshTokenID", true, {
expires: new Date(new Date().getTime() + 31557600000),
})
.json({ success: true });
};sendEmail.js
const nodemailer = require("nodemailer");
const sendEmail = (options) => {
const transporter = nodemailer.createTransport({
service: process.env.EMAIL_SERVICE,
auth: {
user: process.env.EMAIL_USERNAME,
pass: process.env.EMAIL_PASSWORD,
},
});
const mailOptions = {
from: process.env.EMAIL_FROM,
to: options.to,
subject: options.subject,
html: options.text,
};
transporter.sendMail(mailOptions, function (err, info) {
if (err) {
console.log(err);
} else {
console.log(info);
}
});
};
module.exports = sendEmail;发布于 2021-07-27 13:21:39
您已经使用此代码将响应设置为client。
res.status(200).json({
success: true,
data: "A verification mail is send to your email. Please confirm before login",
});但是您有一个方法sendToken(user, 200, res);,我假设您向客户端发送另一个信息,或者您有另一个res.json()、res.send()或res.body(),或者类似于该方法中的那些。
发送到客户端后,不能再次设置标头。
您可以在res.status().json()之后添加一个返回语句,这样就不会执行sendToken()。
或者你可以用你自己的方式。
res.status(200).json({
success: true,
data: "A verification mail is send to your email. Please confirm before login",
});
return;https://stackoverflow.com/questions/68545213
复制相似问题