Обработка данных формы и регистрация пользователей в стеке MERN: проблемы с FormData и проверкой

Я работаю над приложением стека 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>
  )
}

Я просто возился с этим. Я раньше не пробовал делать это таким образом, поэтому не уверен, может ли это быть причиной того, что мои данные внешнего интерфейса недоступны для моего внутреннего интерфейса.

Я все еще многому узнаю о фулстеке, поэтому буду рад любым отзывам и советам! Спасибо за ваше время!

Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
0
50
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

При публикации данных формы здесь:

body: JSON.stringify(userRegisterData)

на самом деле вы отправляете простой объект (поскольку данные userRegisterDatd/form не являются простым объектом JS, поэтому при их преобразовании в строку игнорируются свойства ключ-значение и получается пустой объект {} см. JSON.stringify > Descripton), и ваш сервер получает пустой объект.

Итак, вам нужно получить значения данных формы в виде простого объекта JS с помощью Object.fromEntries(), а затем преобразовать их в строку и отправить как JSON:

Попробуй это:

body: JSON.stringify(Object.fromEntries(userRegisterData))

Это сработало! Большое спасибо! У меня есть еще один вопрос. Я сразу же вернусь к работе над этим, но решил спросить ваше мнение о том, как решить эту проблему. Он правильно отправляет информацию, но мое форматирование неверно. Я отправляю объект, содержащий роли[0]: 'admin' и роли[1]: 'пользователь' вместо свойства roles, содержащего массив со значениями roles[0] и roles[1]. Я думал о том, чтобы сделать цикл for и просто создать еще один объект для отправки в серверную часть в правильном формате. Но я подумал, что должен быть другой путь. Как бы вы это сделали?

yzkael 22.07.2024 02:21

это формат объекта, отправляемого на серверную часть: { имя пользователя: 'jussim', пароль: '123456', submitPassword: '123456', зарплата: '2550', электронная почта: '[email protected]', 'roles[ 0]': 'admin', 'roles[1]': 'user' } Я попытаюсь исправить это в моей функции API-клиента во внешнем интерфейсе, но я не знаю, плохой ли это дизайн в моей форме.

yzkael 22.07.2024 02:26

большой. если ответ решит вашу проблему, вы можете принять его. что касается массива, попробуйте: formData.append(`roles`, JSON.stringify(formDataJson.roles));, а затем на сервере: JSON.parse(req.body.roles), но я не уверен, следует ли изменять валидатор, потому что это строка... хотя вы можете опубликовать это как другой вопрос

traynor 22.07.2024 08:12

сделаю Друг Спасибо еще раз! В итоге я создал цикл for, который просто создает еще один объект, он работает, но он довольно многословен.

yzkael 22.07.2024 08:19

обычно вы используете добавление + JSON.stringify, но я думаю, что Object.entries превращает его в строку... кроме того, немного более грязным способом было бы добавить его как свойство: body: JSON.stringify({...Object.fromEntries(userRegisterData),...r‌​oles}). Я думаю, что в любом случае вам придется изменить валидатор, что немного выходит за рамки вопроса, IMO... да, вы можете легко заменить здесь данные формы простым JSON и избежать всего этого

traynor 22.07.2024 08:23

Другие вопросы по теме