Files
wushu/ht/test/API.md
2026-03-30 02:35:31 +08:00

9.8 KiB
Raw Permalink Blame History

诗词答题 API 文档

基础信息

项目 说明
基础URL /api.php
返回格式 JSON
编码 UTF-8
请求方式 GET / POST 都支持

请求方式说明

接口 推荐方式 原因
获取题目 (question) GET 读取操作,简单可缓存
下一题 (next) GET 读取操作
获取新题 (fetch) GET 读取操作
提交答案 (answer) POST 提交操作,更规范
获取提示 (hint) GET 读取操作
题目列表 (list) GET 读取操作
刷新缓存 (refresh) GET 管理操作
状态统计 (stats) GET 读取操作

通用返回格式

{
    "code": 0,
    "msg": "",
    "data": { ... }
}
字段 类型 说明
code int 状态码0=成功,其他=错误
msg string 提示信息
data object 返回数据

接口列表

1. 获取题目

请求

GET /api.php?action=question&id=0
参数 类型 必填 说明
action string 默认为 question
id int 题目ID默认0

返回

{
    "code": 0,
    "msg": "",
    "data": {
        "id": 0,
        "total": 10,
        "question": "欲把西湖比西子,\"________\"",
        "author": "苏轼",
        "type": "江南",
        "grade": "小学",
        "dynasty": "宋朝",
        "options": [
            {"index": 1, "content": "山色空蒙雨亦奇"},
            {"index": 2, "content": "淡妆浓抹总相宜"},
            {"index": 3, "content": "门前流水尚能西"},
            {"index": 4, "content": "拄杖无时夜叩门"}
        ]
    }
}

2. 获取下一题(自动进度)

请求

GET /api.php?action=next
参数 类型 必填 说明
action string 固定为 next

说明

  • 无需传 id 参数,系统自动记住当前进度(使用 Session
  • 每次刷新自动跳到下一题
  • 如果已经是最后一题,自动回到第 0 题(循环)

使用方式

刷新次数 返回的 id
第 1 次 1
第 2 次 2
第 3 次 3
... ...
第 62 次 0 (循环)

返回

{
    "code": 0,
    "msg": "",
    "data": {
        "id": 1,
        "total": 62,
        "question": "人生得意须尽欢,\"__________\"",
        "author": "李白",
        "type": "豪放",
        "grade": "高中",
        "dynasty": "唐朝",
        "options": [...],
        "prev_id": 0
    }
}

3. 刷新获取新题(推荐)

请求

GET /api.php?action=fetch
参数 类型 必填 说明
action string 固定为 fetch

说明

  • 每次刷新都从百度 API 获取新题目
  • 新题目自动写入本地缓存(去重)
  • 返回本次获取的随机一题
  • API 失败时自动降级使用本地缓存

返回

{
    "code": 0,
    "msg": "",
    "data": {
        "id": null,
        "total": 65,
        "question": "人生得意须尽欢,\"__________\"",
        "author": "李白",
        "type": "豪放",
        "grade": "高中",
        "dynasty": "唐朝",
        "options": [...],
        "from_cache": false,
        "new_questions": 3
    }
}

额外返回字段

字段 类型 说明
from_cache bool 是否来自本地缓存
new_questions int 本次新增题目数量

4. 提交答案

请求方式 1GET简单

GET /api.php?action=answer&id=0&answer=2

请求方式 2POST推荐

POST /api.php
Content-Type: application/x-www-form-urlencoded

action=answer&id=0&answer=2

或使用 JSON

POST /api.php
Content-Type: application/json

{
    "action": "answer",
    "id": 0,
    "answer": "2"
}
参数 类型 必填 说明
action string 固定为 answer
id int 题目ID
answer string 答案序号(1-4)

返回

{
    "code": 0,
    "msg": "",
    "data": {
        "id": 0,
        "correct": true,
        "your_answer": "2",
        "correct_answer": "2",
        "next_id": 1,
        "has_next": true
    }
}

5. 获取提示

请求

GET /api.php?action=hint&id=0
参数 类型 必填 说明
action string 固定为 hint
id int 题目ID

返回

{
    "code": 0,
    "msg": "",
    "data": {
        "id": 0,
        "hint": "这是首描写江南的诗,你在小学学过它。",
        "author": "苏轼",
        "dynasty": "宋朝"
    }
}

6. 获取题目列表

请求

GET /api.php?action=list

返回

{
    "code": 0,
    "msg": "",
    "data": {
        "total": 10,
        "list": [
            {
                "id": 0,
                "question": "欲把西湖比西子,\"________\"...",
                "author": "苏轼",
                "dynasty": "宋朝"
            }
        ]
    }
}

7. 刷新缓存

请求

GET /api.php?action=refresh

说明

  • 强制从百度 API 获取最新题目
  • 合并到本地缓存(去重)

返回

{
    "code": 0,
    "msg": "",
    "data": {
        "refreshed": true,
        "total": 15
    }
}

缓存机制

配置 说明
缓存文件 data/questions.json 本地JSON文件
过期时间 永不过期 永久保存
去重方式 question_content 相同题目不重复存储
降级策略 API失败自动使用本地缓存 原始URL失效也能使用
API 限频 5秒内只请求一次 防止并发请求百度

缓存文件结构

{
    "updated": "2024-01-01 12:00:00",
    "count": 10,
    "questions": [...]
}

性能优化

已实现优化

优化项 说明
静态变量缓存 同一请求内多次读取只加载一次文件
API 请求锁 5秒内多人请求只发一次 API
原子写入 先写临时文件再 rename防止数据损坏
去重优化 只在写入时去重,读取时不处理
超时控制 API 超时 5 秒,连接超时 3 秒

性能预估

场景 响应时间
读取本地缓存 ~2-5ms
API 请求成功 ~200-500ms
API 限频降级 ~1ms直接读缓存
100人并发 无压力(读缓存为主)

查看状态

GET /api.php?action=stats

返回:

{
    "code": 0,
    "data": {
        "total_questions": 149,
        "cache_file_size": "40.5 KB",
        "last_updated": "2026-03-29 05:04:04",
        "memory_usage": "256 KB"
    }
}

错误码

code 说明
0 成功
400 参数错误
404 题目不存在

使用示例

JavaScript

// 获取第一题
fetch('/api.php?action=question&id=0')
    .then(r => r.json())
    .then(d => console.log(d.data.question));

// 获取下一题(自动进度,无需传 id
fetch('/api.php?action=next')
    .then(r => r.json())
    .then(d => console.log(d.data.id, d.data.question));

// 提交答案
fetch('/api.php?action=answer&id=0&answer=2')
    .then(r => r.json())
    .then(d => {
        if(d.data.correct) {
            console.log('回答正确!');
        }
    });

Flutter/Dart

import 'package:dio/dio.dart';

final dio = Dio();

// 获取题目
Future<Map> getQuestion(int id) async {
  final res = await dio.get('/api.php', queryParameters: {
    'action': 'question',
    'id': id,
  });
  return res.data['data'];
}

// 获取下一题(自动进度,无需传 id
Future<Map> getNextQuestion() async {
  final res = await dio.get('/api.php', queryParameters: {
    'action': 'next',
  });
  return res.data['data'];
}

// 提交答案POST 方式)
Future<bool> checkAnswer(int id, String answer) async {
  final res = await dio.post('/api.php', data: {
    'action': 'answer',
    'id': id,
    'answer': answer,
  });
  return res.data['data']['correct'];
}

App 集成建议

方案 1App 自己管理进度(推荐)

使用 ?action=question 接口App 完全控制进度:

class QuizApi {
  int _currentId = 0;
  int _total = 0;

  Future<Map> getQuestion() async {
    final res = await dio.get('/api.php', queryParameters: {
      'action': 'question',
      'id': _currentId,
    });
    final data = res.data['data'];
    _total = data['total'] ?? 0;
    return data;
  }

  Future<Map> submitAnswer(String answer) async {
    final res = await dio.post('/api.php', data: {
      'action': 'answer',
      'id': _currentId,
      'answer': answer,
    });
    return res.data['data'];
  }

  void nextQuestion() {
    _currentId++;
    if (_currentId >= _total) {
      _currentId = 0;
    }
  }

  int get currentId => _currentId;
}

优点

  • 不依赖 SessionApp 完全控制进度
  • 可以随时跳转任意题目
  • 适合多端同步

方案 2使用自动进度

使用 ?action=next 接口API 自动管理:

Future<Map> getNextQuestion() async {
  final res = await dio.get('/api.php', queryParameters: {
    'action': 'next',
  });
  return res.data['data'];
}

优点

  • 简单,无需管理 ID
  • 自动循环

缺点

  • 依赖 Session需要保持 cookie
  • 无法自由跳转题目

方案 3不断获取新题

使用 ?action=fetch 接口,每次都从百度获取新题:

Future<Map> getNewQuestion() async {
  final res = await dio.get('/api.php', queryParameters: {
    'action': 'fetch',
  });
  return res.data['data'];
}

适用场景

  • 想要不断扩展题库
  • 用户每次刷新都可能看到新题