【问题标题】:How to show different content to the users of my web app? MERN stack如何向我的网络应用程序的用户显示不同的内容? MERN 堆栈
【发布时间】:2019-01-29 04:02:27
【问题描述】:

我正在尝试制作一个投票应用程序,每个用户只能投票一次。为了实现这一点,我保存了已经投票的用户的 ip,并将它们与使用该应用程序的用户进行比较。所以如果他的 ip 匹配一个已经在数据库中的,他会得到一个屏幕说他不能再次投票。 问题是,如果一个用户投票了,其他所有用户都会在屏幕上显示他们不能投票。

这是获取用户ip和数据库中所有ip的后端代码,如果投票则发布ip:

const express = require("express");
const router = express.Router();
const ipify = require("ipify");
const mongoose = require("mongoose");
const internalIp = require("internal-ip");

const ipModel = require("../../models/Ip");

// @route   GET api/ip
// @desc    obtener todas las ip de la db
// @access  public
router.get("/", (req, res) => {
  ipModel
    .find()
    .then(ip => {
      res.status(200).json(ip);
    })
    .catch(err => res.status(404).json(err));
});

// @route   POST api/ip
// @desc    Guardar la ip en la db
// @access  public
router.post("/", (req, res) => {
  internalIp
    .v4()
    .then(miip => {
      ipModel
        .findOne({ ip: miip })
        .then(laip => {
          if (laip) {
            return res
              .status(400)
              .json({ ip: "Su voto se ha realizado exitosamente" });
          } else {
            const newIp = new ipModel({
              ip: miip
            });
            newIp.save().then(ip => res.json(newIp));
          }
        })
        .catch(err => res.status(404).json(err));
    })
    .catch(err => res.json(err));
});

// @route   GET api/ip/miip
// @desc    Guardar la ip en la db
// @access  public
router.get("/miip", (req, res) => {
  internalIp
    .v4()
    .then(miip => {
      res.status(200).json(miip);
    })
    .catch(err => res.json(err));
});

module.exports = router;

这是管理前端投票逻辑的组件的代码:

import React, { Component } from "react";
import { Redirect } from "react-router-dom";
import { Container, ListGroup, ListGroupItem, Button } from "reactstrap";
import { CSSTransition, TransitionGroup } from "react-transition-group";
import axios from "axios";

class Votos extends Component {
  constructor() {
    super();
    this.state = {
      carrozas: [],
      ipRegistradas: [],
      miIp: null,
      goToVotos: true
    };
    this.votar = this.votar.bind(this);
  }

  componentDidMount() {
    axios
      .get("/api/ip")
      .then(ips => {
        this.setState(prevState => ({
          ipRegistradas: [...prevState.ipRegistradas, ...ips.data]
        }));
      })
      .catch(err => console.log(err));

    axios
      .get("/api/carrozas")
      .then(carrozasdb => {
        this.setState(prevState => ({
          carrozas: [...prevState.carrozas, ...carrozasdb.data]
        }));
      })
      .catch(err => console.log(err));

    axios
      .get("/api/ip/miip")
      .then(miip => {
        this.setState({
          miIp: miip.data
        });
      })
      .catch(err => console.log(err));
  }

  shouldRedirect() {
    for (var i = 0; i < this.state.ipRegistradas.length; i++) {
      if (this.state.ipRegistradas[i].ip === this.state.miIp) {
        this.setState({
          goToVotos: false
        });
      }
    }
  }

  votar(nom) {
    axios.post("/api/votos", { nombre: nom });
    axios.post("/api/ip");
  }

  render() {
    const { carrozas } = this.state;
    this.shouldRedirect();

    if (this.state.goToVotos === true) {
      return (
        <Container>
          <h3
            style={{
              display: "flex",
              justifyContent: "center",
              alignItems: "center"
            }}
          >
            Votá la mejor carroza...
          </h3>
          <ListGroup>
            <TransitionGroup className="carrozas">
              {carrozas.map(({ _id, nombre, curso }) => (
                <CSSTransition key={_id} timeout={500} classNames="fade">
                  <ListGroupItem
                    style={{
                      display: "flex",
                      justifyContent: "spaceAround"
                    }}
                  >
                    <Button
                      className="votar-btn"
                      color="primary"
                      size="sm"
                      onClick={() => {
                        this.votar(nombre);
                        this.props.history.push("/votoexitoso");
                      }}
                    >
                      Votar
                    </Button>
                    "{nombre}"
                    <p
                      style={{
                        marginLeft: "5rem"
                      }}
                    >
                      {curso}
                    </p>
                  </ListGroupItem>
                </CSSTransition>
              ))}
            </TransitionGroup>
          </ListGroup>
        </Container>
      );
    } else {
      return <Redirect to="votoexitoso" />;
    }
  }
}

export default Votos;

【问题讨论】:

    标签: node.js reactjs express mongoose


    【解决方案1】:

    internal-ip 为您提供您的服务器 IP 地址。要获取客户端 IP 地址,您可以使用 request.connection.remoteAddressrequest.headers['x-forwarded-for'](如果服务器位于代理后面)。

    router.post("/", (req, res) => {
        const ip = req.connection.remoteAddress;
        ...
    

    【讨论】:

    • 使用客户端IP地址代替服务器IP地址如何解决问题?
    • AFAIK 当用户投票时,您将他的 IP 地址存储在数据库中,并且只有在数据库中找不到他的 IP 地址时才允许投票(对吗?)。如果您使用您的服务器 IP 地址,您实际上是在将您的服务器地址与之前存储的服务器地址进行比较,因此每个人都会收到“不能投票”的消息。
    • 我已经尝试过您的解决方案,它奏效了。谢谢你。但我现在有另一个问题。每次我在手机中使用该应用程序投票时,同一设备的数据库中都会保存一个不同的 IP 地址,因此它始终允许投票
    • 一般来说,IP 地址不是识别用户身份的可靠方法,它们是动态的并且会随着时间而变化。如果您需要 100% 确定此用户之前没有投票,请考虑使用其他方法,例如注册。
    • 问题是我不希望用户浪费时间注册。也许如果我使用 cookie 而不是 IP 地址或注册方法?
    猜你喜欢
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多