如何从JavaScript文件获取变量值上传MongoDB而非HTML表单
问题背景
目前已实现HTML表单提交数据到后端、存入MongoDB的基础功能,相关代码如下:
- 前端表单代码:
<form class="container" method="post"> <div class="form-group"> <input class="form-control" name="title"> </div> <textarea class="form-control" name="content"></textarea> <button>add to mongodb</button> </form>
- 后端接收存储代码:
app.post("/", function(req, res) { let newGameData = new gameData ({ score: req.body.title, jumps: req.body.content, }); newGameData.save(); res.redirect('/') })
待实现需求
当前不需要从HTML表单取值,需要获取嵌入页面的独立游戏JS文件里的运行时变量。该JS中定义了两个随游戏进程持续追加数据的全局数组:
var score = []; var jumps = [];
两个数组会随着游戏分数提升、角色触发跳跃操作持续追加数据,需要实现三个核心目标:
- 玩家每次游戏生命结束时,追加对应分数记录
- 定期将游戏运行产生的这部分数据上传至MongoDB存储
- 支持从MongoDB拉取最高分数据,在前端页面展示
之前考虑过先把数据写入JSON文件再上传MongoDB,但不确定方案是否合理、也不清楚具体实现流程,需要可落地的实现思路。
实现方案
不需要先写本地JSON文件再上传,前端运行时产生的JS变量可以直接通过接口提交到后端,流程和你之前写的表单提交逻辑本质一致,只是提交触发时机、提交的数据来源从表单输入框改成了JS运行时变量。浏览器端JS运行在用户本地环境,没有直接写入本地文件的权限,写JSON再上传的方案本身不具备可行性。
1. 后端接口调整
你现有的POST接口可以直接复用,只需要调整参数匹配逻辑,新增JSON请求体解析中间件,再加一个获取最高分的GET接口即可:
// 先加这行中间件,否则后端无法解析前端传的JSON格式请求体,放在路由定义前面 app.use(express.json()) // 调整原有提交数据接口 app.post("/api/gamedata", function(req, res) { let newGameData = new gameData ({ score: req.body.score, // 直接接收前端传过来的score数组/单次分数 jumps: req.body.jumps, // 直接接收前端传过来的jumps数组 recordTime: Date.now() // 可选,加记录时间方便后续做数据统计 }); newGameData.save().then(()=>{ res.send({code:200, msg:"保存成功"}) }).catch(err=>{ res.send({code:500, msg:"保存失败"}) }) }) // 新增获取最高分接口 app.get("/api/highestscore", async function(req, res) { // 按score字段倒序取第一条记录,即为历史最高分 const highestRecord = await gameData.findOne().sort({score: -1}) res.send({ code:200, data: highestRecord?.score || 0 }) })
2. 前端游戏JS逻辑修改
(1)游戏结束时触发数据提交
找到游戏逻辑里判定玩家生命结束的代码位置,在游戏结束的回调函数里直接读取全局的score和jumps变量,通过fetch提交到后端接口即可:
// 在你已有的游戏结束处理函数里加入以下逻辑 function gameOver() { // 保留你原本的游戏结束逻辑,比如弹出结算面板、停止帧动画、重置游戏状态等 // ... // 提交当前局数据到后端 fetch("/api/gamedata", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ score: score, // 直接传入当前全局作用域下的score数组 jumps: jumps // 直接传入当前全局作用域下的jumps数组 }) }).then(res=>res.json()).then(res=>{ if(res.code === 200) { // 提交成功后清空当前局的数组,为下一局游戏做准备 score = [] jumps = [] } }) // 拉取历史最高分渲染到页面 fetch("/api/highestscore").then(res=>res.json()).then(res=>{ if(res.code ===200) { // 将返回的最高分写入页面对应的DOM节点即可 document.querySelector("#highest-score").textContent = res.data } }) }
(2)定期上传备份实现
如果需要在游戏过程中定期上传备份数据、不用等游戏结束再传,直接加个定时任务即可:
// 页面加载完成后启动定时器,每30秒上传一次当前数据,间隔可自行调整 setInterval(()=>{ // 只有当前数组存在数据时才发起请求,避免无意义的空请求 if(score.length >0 || jumps.length>0) { fetch("/api/gamedata", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ score: [...score], // 拷贝一份当前数据传递,避免上传过程中数组变化导致数据异常 jumps: [...jumps] }) }) } }, 30000) // 单位为毫秒
3. 注意事项
- 如果游戏单局时长较短,可以不做定期上传逻辑,仅在游戏结束时传一次数据即可,减少不必要的接口请求。
- 如果需要区分不同玩家的数据,可以在提交数据时额外加上用户标识字段,后端存储时同步记录即可。
- 前端提交前可以对数据做简单校验,避免异常数据写入数据库。
内容的提问来源于stack exchange,提问作者aspiringprogrammer
相关产品推荐
相关产品推荐

