您的当前位置:首页>全部文章>文章详情

【Webman+MySQL答题系统十】前后端联调与全流程测试(收官)

果子发表于:2026-10-05 20:55:47浏览:3次TAG: #PHP #MySql #答题系统

本篇目标

系列收官:UniApp 端封装请求与登录态,串起登录→取卷→作答→交卷→成绩→错题全流程,附 curl 测试清单与踩坑汇总。

第十篇封面

一、联调结构

前后端联调结构图

二、UniApp 请求封装

common/api.js,统一处理 token、401 跳转、错误提示:

const BASE = 'https://quiz.example.com'

function request(path, data = {}, method = 'GET') {
  const token = uni.getStorageSync('token')
  return new Promise((resolve, reject) => {
    uni.request({
      url: BASE + path,
      method,
      data,
      header: token ? { Authorization: 'Bearer ' + token } : {},
      success: res => {
        const body = res.data
        if (body.code === 0) return resolve(body.data)
        if (body.code === 401) {
          uni.removeStorageSync('token')
          uni.reLaunch({ url: '/pages/login/login' })
          return reject(body)
        }
        uni.showToast({ title: body.msg || '请求失败', icon: 'none' })
        reject(body)
      },
      fail: err => {
        uni.showToast({ title: '网络异常', icon: 'none' })
        reject(err)
      }
    })
  })
}

export const login     = d => request('/api/auth/login', d, 'POST')
export const getPaper  = id => request('/api/answer/paper', { paper_id: id })
export const submit    = d => request('/api/answer/submit', d, 'POST')
export const myRecords = () => request('/api/stat/my_records')
export const wrongBook = () => request('/api/stat/wrong_book')

登录成功后 uni.setStorageSync('token', data.token) 即可,后续所有请求自动携带。

三、页面串联

// login.vue 提交
const data = await login({ username, password })
uni.setStorageSync('token', data.token)

// exam.vue 开始答题
const data = await getPaper(this.paperId)
this.paper = data.paper
this.questions = data.questions
this.deadline = Date.now() + this.paper.duration * 60000

// exam.vue 交卷
const data = await submit({
  paper_id: this.paperId,
  answers: this.answers,
  use_seconds: this.usedSeconds
})
uni.showModal({
  title: data.is_pass ? '恭喜及格' : '未能及格',
  content: `得分 ${data.score} / ${data.total_score}`
})

小程序/APP 端没有跨域问题;H5 端若前后端不同域名,在 Webman 里加全局跨域中间件(Access-Control-Allow-Origin 等响应头 + OPTIONS 预检放行)。

四、全流程 curl 清单

# 1. 登录
TOKEN=$(curl -s -X POST http://127.0.0.1:8787/api/auth/login \
  -d "username=zhangsan" -d "password=123456" | jq -r .data.token)

# 2. 试卷列表 -> 组卷数据(管理端)
curl "http://127.0.0.1:8787/api/paper/list?page=1&limit=10"

# 3. 取卷
curl "http://127.0.0.1:8787/api/answer/paper?paper_id=1" \
  -H "Authorization: Bearer $TOKEN"

# 4. 交卷
curl -X POST http://127.0.0.1:8787/api/answer/submit \
  -H "Authorization: Bearer $TOKEN" \
  -d "paper_id=1" -d "use_seconds=353" \
  -d "answers[1]=B" -d "answers[2]=A,C,D" -d "answers[3]=A"

# 5. 成绩 / 统计 / 错题本
curl "http://127.0.0.1:8787/api/stat/my_records" -H "Authorization: Bearer $TOKEN"
curl "http://127.0.0.1:8787/api/stat/paper_stat?paper_id=1"
curl "http://127.0.0.1:8787/api/stat/wrong_book" -H "Authorization: Bearer $TOKEN"

六步全绿,系统闭环验收通过。

五、系列踩坑汇总

坑现象解法
常驻内存不热载改了代码没生效重启 start.php / windows.php
JSON body 取不到post() 返回 nullrawBody()+json_decode,或前端用 form 提交
MySQL 断连偶发 server has gone away升级 webman/database / 用连接池
聚合 SQL 报错only_full_group_by 拒绝执行非聚合列全进 GROUP BY
答案泄露取卷接口带出 answer白名单式组装返回字段
半分判分多选漏选误判全错array_diff 判定真子集

六、还能往哪走

  • 防切屏作弊:前端监听页面隐藏上报,服务端记违规次数;
  • 题目乱序:取卷时 shuffle、提交时按 question_id 判分天然兼容;
  • 导出成绩:webman 里用 phpoffice/phpspreadsheet 导出 Excel;
  • 并发排行榜:redis ZSET 实时榜。

系列总结

十篇走完:需求拆解 → 环境搭建 → 建表 → 题库 → 组卷 → 取卷 → 判分 → 统计 → 鉴权 → 联调。一个数据自洽、防泄题、可扩展的答题系统骨架已经完整落地,剩下的都是在这个骨架上长肉。感谢阅读,有问题欢迎留言交流。