<form>

问题描述 投票:0回答:1

我正在开始我的年终学习项目(截止日期为七月中旬:))。 我正在尝试制作一个小网站,为了脱颖而出,我不是使用 php 而是使用 node.js。

我发现了这项技术,但我已经面临第一个问题。 (在对数据库进行编码时遇到问题)我想要进行身份验证,但无法从

<form>
检索数据。 当我对
log
执行
req.body.password
时,它返回
undefined
,对于
req.body
,则返回
{}
。 我不明白为什么。

这是我已经制作的代码:

index.js

require('dotenv').config();
const express = require("express");
const https = require("https");
const path = require("path");
const fs = require("fs");


const port = process.env.PORT || 4242;
const app = express();

// Analyser les corps de requête au format URL-encoded
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

app.set('views', './views');
app.set('view engine', 'ejs');

app.use('/', require('./controllers/homeController')); 

app.use('/images', express.static(path.join(__dirname, 'images')));

const sslServer = https.createServer({
    key: fs.readFileSync(path.join(__dirname, 'cert', 'key.pem')),
    cert: fs.readFileSync(path.join(__dirname, 'cert', 'cert.pem'))
}, app);
sslServer.listen(port, () => {
    console.log("Le serveur fonctionne !");
    console.log(process.env.PORT)
});

home.ejs

...
<main class="main">
   <div class="parent">
      <form method="post" class="enfant" id="loginForm">
         <input type="password" name="password" placeholder="password" id="pwd" required>
         <button type="submit" id="bouton">valider</button>
      </form>
   </div>
</main>
...
<script>
   document.getElementById("loginForm").addEventListener("submit", function(event) {
      event.preventDefault();
      const formData = new FormData(this);
      fetch('/', {
         method: "POST",
         body: formData
      })
      .then(response => {
         if (response.ok) {
            window.location.href = "/dashboard"; // Rediriger vers la page du tableau de bord si la connexion réussit
         } else {
            return response.text();
         }
      })
      .then(message => {
         document.getElementById("message").innerText = message;
         //alert(message);
      })
      .catch(error => {
         console.error('Error:', error);
      });
   });
</script>

User.js

const mysql = require("mysql2/promise");
require('dotenv').config();

class User {

  constructor(){
    this.dbConnect = mysql.createPool({
      host: process.env.DB_HOST,
      user: process.env.DB_USERNAME,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME
    });
  }

  async get(){
    try{
      const connexion = await this.dbConnect.getConnection();
      const [res, fields] = await connexion.execute(`SELECT * FROM User;`);
      connexion.release();
      return await res;
    }
    catch(err){
      return await err;
    }
    finally{
      this.dbConnect.end();
    }
  }
}
module.exports = User;

homeController.js

const express = require('express');
const limiter = require('express-rate-limit');
const User = require('../models/User');

const app = express();
const homeRegex = /^\/(home)?$/;

// Middleware pour analyser les corps de requête
app.use(express.json());
app.use(express.urlencoded({ extended: true }));

//limiter à 5 tentatives de log sur 5 minutes
const signInlimiter = limiter({ 
    windowMs: 5*60*1000, 
    limit: 1, 
    message: (req, res) => { 
        date = (new Date(req.rateLimit.resetTime)).toLocaleTimeString(); 
        return `Trop de tentatives ! Vous ne pourrez pas retenter avant ${date} ⏰.`; 
    },
    keyGenerator: (req, res) => {req.ip}
});

//REQUETES

app.get(homeRegex, (req, res) => { res.render("home.ejs", { message: "" }); });

// 429 par défaut
app.post(homeRegex, signInlimiter,  async (req, res) => {
    // Vérifier les informations de connexion et renvoyer une réponse appropriée (pour l'instant pwd = password)
    const password  = req.body.password;
    console.log(req.body)
    try {
        const userData = await getUser();
        const pwdData = userData[0].pwd;
        //non haché
        if (password === pwdData) {
            res.status(200).send("Bienvenue 💙🤍❤️");
        } else {
            res.status(401).send("Invalide 💀💀💀");
        }
    } catch (err) {
        
    }
});

async function getUser() {
    let user = new User();
    try {
        const userData = await user.get();
        return JSON.parse(JSON.stringify(userData, null, 2));
    } catch (err) {
        console.log(err);
        return null;
    }
}
module.exports = app;

我已经问过 ChatGPT 但显然它并不强大;b 你能向我解释一下为什么它不起作用吗? 不过,对我来说一切似乎都很好(从我的角度来看,这项技术是新手)。

谢谢。

javascript node.js express ejs mysql2
1个回答
0
投票

为了解释这个问题,我必须首先分享一些有关

express.json()
express.urlencoded()
中间件如何工作的细节。或者直接跳到解决方案。

背景

当您发出 HTTP POST 请求时,正文数据本身基本上只是文本或字节,并且

Content-Type
header 用于告诉服务器应如何解释该数据。 Express 提供的各种正文解析中间件都会查看此标头来决定是否需要采取行动。

例如,查看 ExpressJS 文档,他们正在寻找的默认 Content-Type 值如下:

中间件 内容类型 它有什么作用
express.json()
application/json
将 JSON 文本解析为对象
req.body
express.urlencoded()
application/x-www-form-urlencoded
将 URL 参数(想想:URL 中
?
之后的部分,又名“查询字符串”)解析为对象
req.body
express.raw()
application/octet-stream
将正文作为字节读取到
Buffer
express.text()
text/plain
将正文作为文本读取为字符串,以
req.body

通常,如果使用

<form>
元素进行 POST(即允许浏览器提交表单),您可以通过其
enctype
属性指定以下其中一项,浏览器将在发送之前处理编码要求:

  1. application/x-www-form-urlencoded
    (不指定则默认)
  2. multipart/form-data
    - 上传文件时使用,因为它允许您发送每个部分具有不同
    Content-Type
    的部分数据
  3. text/plain

使用

fetch
时,您可以在选项中手动指定
headers
对象并设置例如
"Content-Type": "application/x-www-form-urlencoded"
,但也有一些具有特殊处理的类可以为您设置它并为您编码数据。这些是:

    您在此处使用的
  1. FormData
    设置
    Content-Type: multipart/form-data
  2. 设定
  3. URLSearchParams
    Content-Type: application/x-www-form-urlencoded

问题

关于您的代码片段的问题。 JavaScript 代码使用

FormData
fetch
。但是,您使用的中间件都不能处理这种类型。

解决方案

如果您打算使用此表单上传文件,则可以继续使用

FormData
,但您需要安装并使用例如
multer
包,用于处理
multipart/form-data
数据的解析。

如果您不打算向此表单添加文件,我建议使用 JSON 或 urlencoded 数据,因为您已经拥有用于解析这些数据的中间件:

JSON

参考:上传JSON数据

fetch("/", {
  method: "POST",
  body: JSON.stringify({
    // inside this event handler, `this` refers to the <form> element's HTMLFormElement instance
    // see https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement/elements
    password: this.elements["password"],
  }),
  headers: {
    "Content-Type": "application/json"
  }
}).then((response) => {
  if (response.ok) {
    window.location.href = "/dashboard"; // Rediriger vers la page du tableau de bord si la connexion réussit
  } else {
    return response.text();
  }
});

urlencoded

fetch("/", {
  method: "POST",
  body: new URLSearchParams({
    password: this.elements["password"],
  })
  // no `headers` because `fetch` recognizes `URLSearchParams` and handles it for us
}).then((response) => {
  if (response.ok) {
    window.location.href = "/dashboard"; // Rediriger vers la page du tableau de bord si la connexion réussit
  } else {
    return response.text();
  }
});

有关

fetch
接受其
body
内容的列表,请参阅:Body - 使用 Fetch API

其他注意事项

有关您的片段的其他注释:

  • homeController.js
    中,不要创建新的 Express 应用程序,而是使用
    express.Router()
    (将
    const app = express()
    替换为
    const app = express.Router()
  • index
    homeController
    文件都应用
    .json()
    .urlencoded()
    中间件。这不是必需的,因为在 app.use("/", require(...)) 之前应用的
    中间件
    也应用于该路由器 (
    homeController.js
    )。考虑只在您实际期望获得此类输入的路由之前执行此操作,因此仅在
    homeController
    中。
© www.soinside.com 2019 - 2024. All rights reserved.