如何使用 Fetch API 实现表单数据的 AJAX 提交与数据库插入

3次阅读

如何使用 Fetch API 实现表单数据的 AJAX 提交与数据库插入

本文详解如何通过现代 JavaScript 的 fetch() 发起 ajax 请求,将 HTML 表单数据异步提交至 Node.js/express 后端(postgresql),并动态更新前端表格,全程规避 CORS 问题,适合初学者快速上手。

本文详解如何通过现代 javascript 的 `fetch()` 发起 ajax 请求,将 html 表单数据异步提交至 node.js/express 后端(postgresql),并动态更新前端表格,全程规避 cors 问题,适合初学者快速上手。

在构建前后端分离的 Web 应用时,避免页面刷新、实现“无感”数据提交是核心体验之一。本教程将手把手带你完成:点击「Send to DB」按钮后,自动收集表单字段 → 以 json 格式发送 POST 请求至 /mine_info 接口 → 成功插入 PostgreSQL 数据库 → 控制台反馈结果。整个流程不依赖传统表单 action 提交,完全由 JavaScript 驱动,符合现代前端开发实践。

✅ 前端关键改造:监听表单提交 + 序列化数据

首先,为

添加唯一 ID(如 id=”myForm”),便于精准获取 dom 元素:

<form id="myForm" class="form">   <button class="exit" id="closeButton" onclick="delRow()">х</button>   <div class="string">     <label for="id">№:</label>     <input type="number" id="id" name="id" required>   </div>   <div class="string">     <label for="N_m">Number:</label>     <input type="text" id="N_m" name="n_m" required>   </div>   <div class="string">     <label for="name">Name:</label>     <input type="text" id="name" name="name_m" required>   </div>   <div class="string">     <label for="Adr">Address:</label>     <input type="text" id="Adr" name="Adr_m">   </div>   <div class="string">     <label for="Full_name">Full name of the director:</label>     <input type="text" id="Full_name" name="director" required>   </div>   <div class="string">     <label for="Phone">Phone number:</label>     <input type="tel" id="Phone" name="Phone_number" placeholder="Например +00000000000" required>   </div>   <button type="submit" id="contact">Send to DB</button> </form>

接着,在 script.js 中添加表单提交事件监听器(务必调用 e.preventDefault() 阻止默认跳转):

const form = document.getElementById('myForm');  form.addEventListener('submit', async (e) => {   e.preventDefault(); // 关键:阻止页面刷新    // 使用 FormData 自动收集所有带 name 属性的输入项   const formData = new FormData(form);   const data = Object.fromEntries(formData.entries());    console.log('Submitting data:', data); // 调试用    try {     const response = await fetch('/mine_info', {       method: 'POST',       headers: {         'Content-Type': 'application/json',       },       body: JSON.stringify(data),     });      if (!response.ok) {       throw new Error(`http error! status: ${response.status}`);     }      const result = await response.text(); // 注意:后端用 res.send() 返回文本,故用 .text()     console.log('Success:', result);      // ✅ 可选增强:提交成功后清空表单 & 关闭弹窗     form.reset();     document.querySelector('.popup').classList.remove('popup_open');     document.querySelector('.form').classList.remove('open');      // ✅ 可选增强:刷新表格数据(见下文)     loadTableData();    } catch (error) {     console.error('Submission failed:', error);     alert('提交失败,请检查网络或后端服务是否运行中。');   } });

⚠️ 重要注意事项

  • 后端 bodyParser.json() 已启用,因此前端必须设置 ‘Content-Type’: ‘application/json’ 并 JSON.stringify();
  • 若后端改用 res.json({ message: ‘…’ }),则前端需改为 await response.json();
  • 表单字段 name 属性值(如 n_m, name_m)必须与后端 SQL 参数名严格一致(见 createRow 函数中解构的 n_mine, name_mine),否则数据库插入会因参数缺失失败。

✅ 后端校验:确保字段映射正确

检查你的 createRow 函数中解构的字段名是否与前端 name 属性匹配:

// ❌ 错误示例(前端 name="n_m",但后端期待 n_mine) const { n_mine, name_mine, ... } = request.body;  // ✅ 正确做法:保持前后端字段名统一 // 前端 input name="n_m" → 后端解构为 n_m const { n_m, name_m, Adr_m, director, Phone_number } = request.body;  pool.query(   'INSERT INTO mine_info (n_mine, name_mine, adress, full_name_of_direcor, phone_number) VALUES ($1, $2, $3, $4, $5) RETURNING *',   [n_m, name_m, Adr_m, director, Phone_number], // 顺序与 SQL 占位符严格对应   (error, results) => { /* ... */ } );

建议统一命名风格(如全小写+下划线),避免大小写或拼写差异导致 undefined 插入。

✅ 进阶:提交后自动刷新表格(可选)

为提升用户体验,可在提交成功后重新拉取最新数据并渲染表格:

async function loadTableData() {   try {     const response = await fetch('/mine_info');     const rows = await response.json();      const tableBody = document.querySelector('#mine_info tbody') ||                        document.querySelector('#mine_info').insertRow(0).parentNode; // 兼容无 tbody 情况      // 清空现有数据行(保留表头)     while (tableBody.rows.length > 1) {       tableBody.deleteRow(1);     }      // 插入新数据     rows.forEach((row, index) => {       const tr = tableBody.insertRow();       tr.innerHTML = `         <td><p>${index + 1}</p><div class="aritcle_card flexRow">                                                         <div class="artcardd flexRow">                                                                 <a class="aritcle_card_img" href="/ai/1162" title="暗壳AI"><img                                                                                 src="https://img.php.cn/upload/ai_manual/000/000/000/175680095316609.png" alt="暗壳AI"  onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>                                                                 <div class="aritcle_card_info flexColumn">                                                                         <a href="/ai/1162" title="暗壳AI">暗壳AI</a>                                                                         <p>Ark.art 包罗万象的艺术方舟,友好高效的设计助手</p>                                                                 </div>                                                                 <a href="/ai/1162" title="暗壳AI" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>                                                         </div>                                                 </div></td>         <td><p>${row.n_mine || ''}</p></td>         <td><p>${row.name_mine || ''}</p></td>         <td><p>${row.adress || ''}</p></td>         <td><p>${row.full_name_of_direcor || ''}</p></td>         <td><p>${row.phone_number || ''}</p></td>       `;     });   } catch (err) {     console.error('Failed to reload table:', err);   } }

并在提交成功回调中调用 loadTableData(),即可实现“所见即所得”的实时同步。

✅ CORS 问题?本地开发请配置代理(推荐)

若你在 http://localhost:5500(VS Code Live Server)访问页面,而 Node.js 后端运行在 http://localhost:3000,浏览器会因跨域拦截请求。不建议在生产环境禁用 CORS,开发阶段推荐两种安全方案:

  1. 前端代理(推荐):使用 vite 或 webpack-dev-server 配置 proxy,将 /mine_info 请求转发至 http://localhost:3000;
  2. 后端启用 CORS:安装 cors 中间件
    npm install cors
    const cors = require('cors'); app.use(cors()); // 允许所有源(开发用),生产环境应限制 origin

至此,你已掌握一个完整、健壮、可扩展的 AJAX 表单提交链路。从 DOM 操作、数据序列化、Fetch 请求、错误处理到用户体验优化,每一步都直击实际开发痛点。坚持练习,你离独立开发全应用只差一次 npm start 的距离。

text=ZqhQzanResources