Я работаю над приложением стека MERN, и у меня возникли проблемы с регистрацией нового пользователя. У меня есть форма во внешнем интерфейсе, которая собирает пользовательские данные и отправляет их на серверную часть. Данные формы включают в себя такие поля, как имя пользователя, пароль, подтверждение пароля, зарплата, роли и адрес электронной почты.
Проблема в том, что данные моей формы неправильно обрабатываются на серверной стороне.
Он достигает правильных конечных точек, но когда я регистрирую запрос, все проверенные значения устанавливаются как неопределенные, даже если API-клиент внешнего интерфейса правильно их получает.
Я использую экспресс-валидатор для проверки соответствующего поля. Я не уверен, нужно ли мне проверять каждое поле, даже если это не требуется моделью пользователя.
Это соответствующие конечные точки, а также модель пользователя.
//интерфейсный apiClient
export const createUser = async(userRegisterData : FormData)=>{
console.info(userRegisterData);
const response = await fetch(${API_BASE_URI}/api/user/,{
method:"POST",
credentials: "include",
headers:{
"Content-Type": "application/json"
},
body: JSON.stringify(userRegisterData),
});
if (!response.ok) {
throw new Error("Failed to register new user");
}
const data = await response.json();
return data;
}
//Пример зарегистрированной информации
FormData(6) { username → "jussim", password → "123456", confirmPassword → "123456", salary → "2550", email → "[email protected]", "roles[0]" → "admin" }
//BACKEND конечные точки // Маршрутизация и экспресс-валидатор
router.post(
"/",
[
check("username", "Username is required").isString(),
check('password',"Password must be at least 6 characters").isLength({min: 6}),
check("roles", "Roles are required").isArray(),
check("email","Email is required").isEmail(),
],verifyToken,
userRegister
);
//Промежуточное программное обеспечение verifyToken
export const verifyToken = async(req: Request, res: Response, next: NextFunction)=>{
const token = req.cookies["auth_cookie"];
if (!token){
return res.status(401).json({message:"Unauthorized"});
}
try {
const decoded = jwt.verify(token,process.env.JWT_SECRET_KEY as string);
req.userInfo = (decoded as JwtPayload).userInfo;
next();
} catch (error) {
console.info(error);
res.status(401).json({message: "Unauthorized"});
}
}
//контроллер userRegister
export const userRegister = async (req: Request, res: Response) => {
const errors = validationResult(req);
console.info(errors.array());
if (!errors.isEmpty()) {
return res.status(400).json({ message: errors.array() });
}
try {
const { username, password, roles, email } = req.body;
const isMatch = await User.findOne({
username: username,
});
if (isMatch) {
return res.status(400).json({ message: "User already exists" });
}
const hashedPassword = await bcrypt.hash(password, 10);
const newUser = new User({
username,
password: hashedPassword,
roles,
email,
createdBy: req.userInfo.userId,
});
await newUser.save();
res.status(200).json({ message: "User registered succesfully!" });
} catch (error) {
console.info(error);
res.status(500).json({ message: "Internal Server Error 500" });
}
};
//Модель пользователя
export interface UserType {
username: string;
password: string;
salary: number;
roles: string[];
email: string;
isActive: boolean;
createdBy: string;
}
const userSchema = new mongoose.Schema(
{
username: { type: String, required: true, unique: true },
password: { type: String, required: true, minlength: 6 },
salary: {type: Number, required: true, default: 2550},
roles: { type: [String], required: true, default: ["client"] },
email: { type: String, required: true, unique: true },
isActive: { type: Boolean, required: true, default: false },
createdBy: { type: String, required: true },
},
{
timestamps: true,
}
);
const User = mongoose.model<UserType & mongoose.Document>("user", userSchema);
Когда я писал этот пост, я заметил некоторые ошибки, например, отсутствие поля зарплаты на моем контроллере. Тем не менее, я не знаю, является ли это причиной того, что никакая информация не доходит до контроллера.
Когда я зарегистрировал error.array(), все значения оказались неопределенными. Это заставляет меня поверить, что это невозможно «прочитать» (? Честно говоря, я понятия не имею, что мне нужно делать. Или как я могу сделать так, чтобы информацию можно было хотя бы использовать из серверной части.
В случае необходимости я практиковался в использовании useFormContext, поэтому моя форма выглядит так:
interface Props{
handleRegister: (formData: FormData)=> void;
isLoading: boolean;
}
export interface UserRegisterFormData {
username: string;
password: string;
confirmPassword: string;
salary: number;
roles: string[];
email: string;
}
const ManageUserRegisterForm = ({handleRegister,isLoading}:Props) => {
const formMethods = useForm<UserRegisterFormData>()
const {handleSubmit} = formMethods;
const onSubmit = handleSubmit((formDataJson:UserRegisterFormData)=>{
const formData = new FormData();
formData.append('username',formDataJson.username);
formData.append('password',formDataJson.password);
formData.append('confirmPassword',formDataJson.confirmPassword);
formData.append('salary', formDataJson.salary.toString());
formData.append('email',formDataJson.email);
formDataJson.roles.forEach((role,index)=>{
formData.append(`roles[${index}]`, role);
})
handleRegister(formData);
})
return (
<FormProvider {...formMethods}>
<form className = "flex flex-col gap-10" onSubmit = {onSubmit}>
<FirstPart/>
<SecondPart/>
<span>
<button type = "submit" disabled = {isLoading} className = "bg-blue-600 text-white p-2 font-bold hover:bg-blue-500 text-xl disabled:bg-gray-500">
{isLoading ? "Loading..." : "Submit"}
</button>
</span>
</form>
</FormProvider>
)
}
Я просто возился с этим. Я раньше не пробовал делать это таким образом, поэтому не уверен, может ли это быть причиной того, что мои данные внешнего интерфейса недоступны для моего внутреннего интерфейса.
Я все еще многому узнаю о фулстеке, поэтому буду рад любым отзывам и советам! Спасибо за ваше время!
При публикации данных формы здесь:
body: JSON.stringify(userRegisterData)
на самом деле вы отправляете простой объект (поскольку данные userRegisterDatd
/form не являются простым объектом JS, поэтому при их преобразовании в строку игнорируются свойства ключ-значение и получается пустой объект {}
см. JSON.stringify > Descripton), и ваш сервер получает пустой объект.
Итак, вам нужно получить значения данных формы в виде простого объекта JS с помощью Object.fromEntries(), а затем преобразовать их в строку и отправить как JSON:
Попробуй это:
body: JSON.stringify(Object.fromEntries(userRegisterData))
это формат объекта, отправляемого на серверную часть: { имя пользователя: 'jussim', пароль: '123456', submitPassword: '123456', зарплата: '2550', электронная почта: '[email protected]', 'roles[ 0]': 'admin', 'roles[1]': 'user' } Я попытаюсь исправить это в моей функции API-клиента во внешнем интерфейсе, но я не знаю, плохой ли это дизайн в моей форме.
большой. если ответ решит вашу проблему, вы можете принять его. что касается массива, попробуйте: formData.append(`roles`, JSON.stringify(formDataJson.roles));
, а затем на сервере: JSON.parse(req.body.roles)
, но я не уверен, следует ли изменять валидатор, потому что это строка... хотя вы можете опубликовать это как другой вопрос
сделаю Друг Спасибо еще раз! В итоге я создал цикл for, который просто создает еще один объект, он работает, но он довольно многословен.
обычно вы используете добавление + JSON.stringify, но я думаю, что Object.entries
превращает его в строку... кроме того, немного более грязным способом было бы добавить его как свойство: body: JSON.stringify({...Object.fromEntries(userRegisterData),...roles})
. Я думаю, что в любом случае вам придется изменить валидатор, что немного выходит за рамки вопроса, IMO... да, вы можете легко заменить здесь данные формы простым JSON и избежать всего этого
Это сработало! Большое спасибо! У меня есть еще один вопрос. Я сразу же вернусь к работе над этим, но решил спросить ваше мнение о том, как решить эту проблему. Он правильно отправляет информацию, но мое форматирование неверно. Я отправляю объект, содержащий роли[0]: 'admin' и роли[1]: 'пользователь' вместо свойства roles, содержащего массив со значениями roles[0] и roles[1]. Я думал о том, чтобы сделать цикл for и просто создать еще один объект для отправки в серверную часть в правильном формате. Но я подумал, что должен быть другой путь. Как бы вы это сделали?