【问题标题】:How do I check if email already exists using MERN如何使用 MERN 检查电子邮件是否已存在
【发布时间】:2020-02-27 20:04:56
【问题描述】:

我有一个注册视图,我正在尝试检查电子邮件是否已经存在,我已经撤消了反应代码,以便您可以很好地了解结构。

电子邮件在架构中被设置为唯一的。

授权控制器

const { check, validationResult } = require("express-validator");
const jwt = require("jsonwebtoken");
const passport = require("passport");
require("../passport");

const Users = require("../models/user");

let validations = [
  check("email")
    .isEmail()
    .withMessage("The email you have entered is not valid")
    .contains("@")
    .withMessage("The email you have entered does not contain an @"),

  check("password")
    .isLength({ min: 5 })
    .withMessage("The password must have at least 5 characters")
];

// Throw error if the key doesn't exist
if (!process.env.JWT_SECRET) {
  console.error("Cannot find JWT key");
}

function generateWebToken(user) {
  return jwt.sign(user, process.env.JWT_SECRET, {
    subject: user.email,
    expiresIn: "7d",
    algorithm: "HS256"
  });
}

/* POST register a user if one doesn't already exist */
module.exports.register = [
  ...validations,
  (req, res) => {
    // Get validation errors from the request
    const errors = validationResult(req);
    // Return the errors
    if (!errors.isEmpty()) {
      return res.status(422).json({ error: errors.array() });
    }

    let hashedPassword = Users.hashPassword(req.body.password);

    Users.findOne({ email: req.body.email })
      .then(function(user) {
        if (user) {
          return res
            .status(400)
            .send(`An account with the email ${req.body.email} already exists`);
        } else {
          Users.create({
            email: req.body.email,
            password: hashedPassword
          })
            .then(function(user) {
              res.status(201).json(user);
            })
            .catch(function(err) {
              console.error(err);
              res.status(500).send(`Error ${err}`);
            });
        }
      })
      .catch(function(err) {
        console.error(err);
        res.status(500).send(`Error ${err}`);
      });
  }
];

Register.js(反应组件)

import React, { Component } from "react";

const initalState = {
  email: "",
  password: "",
  emailErr: "",
  passwordErr: ""
};

class Register extends Component {
  constructor(props) {
    super(props);
    this.state = {
      initalState,

      successMsg: ""
    };

    this.handleSubmit = this.handleSubmit.bind(this);
  }

  validate = () => {
    let emailErr = "";
    let passwordErr = "";

    // Email validation
    if (!this.state.email) {
      emailErr = "Please enter an email";
    }

    // Password validation
    if (!this.state.password) {
      passwordErr = "Please enter your password";
    }

    if (emailErr || passwordErr) {
      this.setState({ emailErr, passwordErr });
      return false;
    }

    return true;
  };

  onEmailChange(event) {
    this.setState({ email: event.target.value });
  }

  onPasswordChange(event) {
    this.setState({ password: event.target.value });
  }

  handleSubmit(event) {
    event.preventDefault();
    const isValid = this.validate();

    if (isValid) {
      fetch("/api/auth/register", {
        method: "POST",
        body: JSON.stringify(this.state),
        headers: {
          Accept: "application/json",
          "Content-Type": "application/json"
        }
      })
        .then(res => res.json())
        .then(this.setState({ successMsg: true }), this.setState(initalState));
    }
  }

  render() {
    return (
      <>
        <div className='block md:flex md:flex-column h-full'>
          <div className='p-12 w-full text-center text-gray-800'>
            <h1 className='title'>Register</h1>

            {this.state.successMsg && (
              <div
                className='w-full m-auto max-w-lg mb-10 bg-green-100 border border-green-400 text-green-700 px-4 py-3 rounded relative'
                role='alert'
              >
                <strong className='font-bold'>Holy smokes! </strong>
                <span className='block sm:inline'>
                  Account has been created
                </span>
              </div>
            )}

            <form className='w-full m-auto max-w-lg'>
              <div className='flex flex-wrap -mx-3'>
                <div className='w-full px-3 mb-6'>
                  <label htmlFor='email'>Email Address</label>

                  <input
                    id='email'
                    type='text'
                    placeholder='johndoe@example.co.uk'
                    value={this.state.email || ""}
                    onChange={this.onEmailChange.bind(this)}
                  />

                  <p className='my-2 text-red-500 text-xs'>
                    {this.state.emailErr}
                  </p>
                </div>
              </div>

              <div className='flex flex-wrap -mx-3'>
                <div className='w-full px-3 mb-6'>
                  <label htmlFor='password'>Password</label>

                  <input
                    id='password'
                    type='password'
                    placeholder='*********'
                    value={this.state.password || ""}
                    onChange={this.onPasswordChange.bind(this)}
                  />

                  <p className='my-2 text-red-500 text-xs'>
                    {this.state.passwordErr}
                  </p>
                </div>
              </div>

              <div className='flex'>
                <button
                  className='btn'
                  type='button'
                  onClick={this.handleSubmit.bind(this)}
                >
                  Send
                </button>
              </div>
            </form>
          </div>
        </div>
      </>
    );
  }
}

export default Register;

不确定是否可以通过快速验证或最好的解决方案是什么。

【问题讨论】:

  • 问题是什么?你有错误吗?
  • 问题在标题中,我正在尝试找到如何检查电子邮件是否已经存在的最佳解决方案
  • 那么你想要代码审查吗?最好发到codereview.stackexchange.com
  • 从来没有说过我想要代码审查,我正在尝试找到检查电子邮件是否存在的最佳方法。我尝试了一些东西,但恢复了这个问题的代码,看看是否有人根据当前代码有更好的解决方案。
  • 我发现您的代码没有问题,您正在正确检查用户是否已经注册,并发送错误。

标签: javascript node.js reactjs express mongoose


【解决方案1】:

上面的代码看起来不错,因为这行代码明确检查 MongoDB 中的电子邮件重复

>if (user) {
        >  return res
          >  .status(400)
          >  .send(`An account with the email ${req.body.email} already exists`);
       > } else {...

【讨论】:

  • 我明白了,但是如何在我的反应表单中输出该错误?
  • 尝试在前端代码的 Promise 中添加一个 catch 块。
  • >.then(res => res.json()) > .then(this.setState({ successMsg: true }), >this.setState(initalState)).catch.... .........
【解决方案2】:

这里是显示注册 api 错误的完整解决方案(快速验证和用户已注册错误)

我试图模仿你的 api 和 react 应用程序,但进行了大量重构:

1-) 在 api 中,我们需要以可读的方式转换表达验证错误:

通常它的验证错误在这样的数组中:

{
    "error": [
        {
            "value": "abcdef@net",
            "msg": "The email you have entered is not valid",
            "param": "email",
            "location": "body"
        },
        {
            "value": "12",
            "msg": "The password must have at least 5 characters",
            "param": "password",
            "location": "body"
        }
    ]
}

使用以下代码,我将错误消息转换为这种格式,以便在 react 应用程序中按字段名称轻松访问:

{
    "errors": {
        "email": "The email you have entered is not valid",
        "password": "The password must have at least 5 characters"
    }
}

注册路线:

const { check, validationResult } = require("express-validator");
const bcrypt = require("bcryptjs");
const { User } = require("../models/user");
const express = require("express");
const router = express.Router();

let validations = [
  check("email")
    .isEmail()
    .withMessage("The email you have entered is not valid"),

  check("password")
    .isLength({ min: 5 })
    .withMessage("The password must have at least 5 characters")
];

router.post("/register", validations, async (req, res) => {
  const errors = validationResult(req);
  if (!errors.isEmpty()) {
    const err = {};
    errors.array().forEach(error => {
      err[error.param] = error.msg;
    });
    return res.status(422).json({ errors: err });
  }

  const { email, password } = req.body;

  try {
    let user = await User.findOne({ email });
    if (user) return res.status(400).send("User already registered.");

    user = new User({ email, password });
    const salt = await bcrypt.genSalt(10);
    user.password = await bcrypt.hash(user.password, salt);
    user = await user.save();

    res.send(user);
  } catch (err) {
    console.log(err);
    res.status(500).send("Something went wrong");
  }
});

module.exports = router;

在 react 方面,我使用 axios 而不是 fetch,因为使用 axios 处理错误要容易得多:

import React, { Component } from "react";
import axios from "axios";

class App extends Component {
  state = {
    email: "",
    password: "",
    fieldErrors: {},
    registerError: null
  };

  handleSubmit = async e => {
    e.preventDefault();

    this.setState({
      fieldErrors: {},
      registerError: null
    })

    const { email, password } = this.state;

    try {
      const response = await axios.post(
        "https://express-validator-auth.herokuapp.com/api/users/register",
        { email, password }
      );
      console.log(response.data);
      alert("Registered");
    } catch (error) {
      if (error.response && error.response.data) {
        if (error.response.data.errors) {
          this.setState({
            fieldErrors: error.response.data.errors
          });
        } else {
          this.setState({
            registerError: error.response.data
          });
        }
      } else {
        console.log(error);
      }
    }
  };

  handleChange = e => {
    this.setState({
      [e.target.name]: e.target.value
    });
  };

  render() {
    const { email, password, fieldErrors, registerError } = this.state;

    return (
      <div>
        <form onSubmit={this.handleSubmit}>
          <div className="form-group">
            <label>Email</label>
            <input
              type="text"
              className={
                !fieldErrors.email ? "form-control" : "form-control is-invalid"
              }
              name="email"
              value={email}
              onChange={this.handleChange}
            />
            {fieldErrors.email && (
              <div className="invalid-feedback">{fieldErrors.email}</div>
            )}
          </div>
          <div className="form-group">
            <label>Password</label>
            <input
              type="password"
              className={
                !fieldErrors.password
                  ? "form-control"
                  : "form-control is-invalid"
              }
              name="password"
              value={password}
              onChange={this.handleChange}
            />
            {fieldErrors.password && (
              <div className="invalid-feedback">{fieldErrors.password}</div>
            )}
          </div>
          <button type="submit" className="btn btn-primary">
            Submit
          </button>
          {registerError && (
            <div className="alert alert-danger" role="alert">
              {registerError}
            </div>
          )}
        </form>
        <br />
        {JSON.stringify(this.state)}
      </div>
    );
  }
}

export default App;

因此,当发生验证错误时,表单将如下所示:

当出现“用户已注册错误”时,表单验证将如下所示:

可以从此代码框访问 React 应用程序: https://codesandbox.io/s/gracious-mccarthy-kluor

【讨论】:

  • @nightcode 这个答案对你有帮助吗?你检查了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-10
  • 2017-01-28
  • 1970-01-01
  • 1970-01-01
  • 2012-08-30
  • 1970-01-01
相关资源
最近更新 更多