You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将HTML表单提交至Node.js处理后返回数据至指定页面的实现疑问

解决方法:在/search_result页面展示筛选后的菜谱结果

你现在遇到的核心问题是直接用res.json()把结果返回成纯文本JSON,浏览器自然就会直接显示这个原始文本。好在你已经配置了EJS模板引擎,正好可以用它来渲染美观的结果页面;如果想要无刷新体验,也可以用AJAX异步提交表单来动态展示结果。下面给你两种可行的方案:

方案一:服务器端渲染(基于EJS模板)

这是最贴合你现有配置的方式,无需额外前端框架就能实现页面跳转式的结果展示。

1. 先修正HTML表单的复选框问题

你原来的复选框name属性都设成了beef_roast,这样后端只能拿到最后一个选中的值,必须改成统一的name搭配不同的value,才能正确收集用户选中的食材:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Recipes</title>
</head>
<body class="container">
  <main>
    <form action="/search_result" method="post">
      <input type="checkbox" name="ingredients" value="beef"> Beef
      <input type="checkbox" name="ingredients" value="pork"> Pork
      <input type="checkbox" name="ingredients" value="fish"> Fish
      <button type="submit" class="btn btn-default">Search recipe</button>
    </form>
  </main>
</body>
</html>

2. 准备菜谱JSON数据源

在项目根目录创建recipes.json文件,示例内容如下(你可以根据实际需求修改):

[
  {
    "name": "家常炖牛肉",
    "link": "/recipes/beef-stew",
    "requiredIngredients": ["beef"]
  },
  {
    "name": "香煎猪排",
    "link": "/recipes/pork-chop",
    "requiredIngredients": ["pork"]
  },
  {
    "name": "柠檬烤鱼",
    "link": "/recipes/grilled-fish",
    "requiredIngredients": ["fish"]
  },
  {
    "name": "海陆双拼饭",
    "link": "/recipes/meat-combo",
    "requiredIngredients": ["beef", "fish"]
  }
]

3. 修改Node.js路由逻辑

现在要读取JSON文件,根据用户选中的食材筛选菜谱,然后渲染EJS模板返回页面,而不是直接返回JSON:

var express = require('express');
var app = express();
const bodyParser = require("body-parser");
const fs = require('fs'); // 引入文件系统模块读取JSON

app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

// 读取菜谱JSON数据的工具函数
const getRecipes = () => {
  const rawData = fs.readFileSync('./recipes.json', 'utf8');
  return JSON.parse(rawData);
};

// 首页路由(展示食材选择表单)
app.get('/', function(req, res) {
  res.sendFile(__dirname + '/index.html'); // 假设你的HTML文件名为index.html
});

// 处理表单提交,返回结果页面
app.post('/search_result', function(req, res) {
  // 处理用户未选中任何食材的情况,默认设为空数组
  const selectedIngredients = req.body.ingredients || [];
  const allRecipes = getRecipes();
  
  // 筛选逻辑:只保留所有必需食材都被用户选中的菜谱
  const availableRecipes = allRecipes.filter(recipe => {
    return recipe.requiredIngredients.every(ing => selectedIngredients.includes(ing));
  });

  // 渲染EJS模板,把筛选后的菜谱数据传过去
  res.render('search_result', { recipes: availableRecipes });
});

app.listen(3000, () => {
  console.log('服务器运行在端口3000');
});

4. 创建EJS结果模板

在项目根目录新建views文件夹(Express默认会从这里读取模板),然后创建search_result.ejs:

<!DOCTYPE html>
<html lang="en">
<head>
  <title>菜谱搜索结果</title>
</head>
<body class="container">
  <main>
    <h1>可用菜谱</h1>
    <% if (recipes.length === 0) { %>
      <p>没有找到符合你所选食材的菜谱哦~</p>
    <% } else { %>
      <ul>
        <% recipes.forEach(recipe => { %>
          <li><a href="<%= recipe.link %>"><%= recipe.name %></a></li>
        <% }) %>
      </ul>
    <% } %>
    <a href="/">返回食材选择页</a>
  </main>
</body>
</html>

这样提交表单后,服务器会自动完成筛选并渲染出格式化的结果页面,不再是纯文本JSON。

方案二:AJAX异步提交(无刷新展示结果)

如果想要页面不跳转,直接在当前页动态展示结果,可以用原生JS的fetch API实现:

1. 修改HTML表单(去掉跳转逻辑,添加结果展示区域)

<!DOCTYPE html>
<html lang="en">
<head>
  <title>Recipes</title>
</head>
<body class="container">
  <main>
    <form id="ingredientForm">
      <input type="checkbox" name="ingredients" value="beef"> Beef
      <input type="checkbox" name="ingredients" value="pork"> Pork
      <input type="checkbox" name="ingredients" value="fish"> Fish
      <button type="submit" class="btn btn-default">Search recipe</button>
    </form>
    <!-- 用来动态展示结果的区域 -->
    <div id="recipeResults"></div>
  </main>
  <script>
    // 监听表单提交事件
    document.getElementById('ingredientForm').addEventListener('submit', async function(e) {
      e.preventDefault(); // 阻止表单默认跳转行为
      
      // 收集用户选中的食材
      const formData = new FormData(this);
      const ingredients = Array.from(formData.getAll('ingredients'));
      
      // 发送异步POST请求到服务器
      const response = await fetch('/search_recipes', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ ingredients })
      });
      
      const recipes = await response.json();
      
      // 动态渲染结果到页面
      const resultsDiv = document.getElementById('recipeResults');
      if (recipes.length === 0) {
        resultsDiv.innerHTML = '<p>没有找到符合你所选食材的菜谱哦~</p>';
      } else {
        const recipeList = recipes.map(recipe => `<li><a href="${recipe.link}">${recipe.name}</a></li>`).join('');
        resultsDiv.innerHTML = `<h1>可用菜谱</h1><ul>${recipeList}</ul>`;
      }
    });
  </script>
</body>
</html>

2. 修改Node.js路由(新增处理AJAX请求的接口)

var express = require('express');
var app = express();
const bodyParser = require("body-parser");
const fs = require('fs');

app.set('view engine', 'ejs');
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

const getRecipes = () => {
  const rawData = fs.readFileSync('./recipes.json', 'utf8');
  return JSON.parse(rawData);
};

// 首页路由
app.get('/', function(req, res) {
  res.sendFile(__dirname + '/index.html');
});

// 处理AJAX请求的接口,返回JSON格式的筛选结果
app.post('/search_recipes', function(req, res) {
  const selectedIngredients = req.body.ingredients || [];
  const allRecipes = getRecipes();
  
  const availableRecipes = allRecipes.filter(recipe => {
    return recipe.requiredIngredients.every(ing => selectedIngredients.includes(ing));
  });

  res.json(availableRecipes);
});

app.listen(3000, () => {
  console.log('服务器运行在端口3000');
});

这样用户点击搜索按钮后,页面不会跳转,而是在当前页面动态加载并展示结果,体验更流畅。


内容的提问来源于stack exchange,提问作者rmarques

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 06:47:51