11 KiB
11 KiB
古诗文答题系统 API 文档
文件信息
- 文件路径:
p1/api.php - 功能描述: 古诗文题目获取与答题系统
- 编码格式: UTF-8
- 响应格式: JSON
安全认证
Key 认证机制
API 采用动态 Key 认证,防止接口被滥用。
认证原理
- 客户端生成 Key: 使用
SHA256(时间戳 + 密钥)生成 - 服务端验证: 验证 Key 是否在有效期内(默认 300 秒)
- Key 更新: 每次成功请求后,服务端返回新的
new_key
密钥配置
- 前端:
api.js中的SECRET_KEY变量 - 后端:
api.php中的SECRET_KEY常量 - 默认密钥:
tzgsc_2026_secret_key
Key 生成算法
PHP
<?php
define('SECRET_KEY', 'tzgsc_2026_secret_key');
function generate_key() {
$timestamp = time();
$data = $timestamp . SECRET_KEY;
return hash('sha256', $data);
}
// 使用示例
$key = generate_key();
$url = "api.php?id=1&key=" . urlencode($key);
JavaScript (Node.js)
const crypto = require('crypto');
const SECRET_KEY = 'tzgsc_2026_secret_key';
function generateKey() {
const timestamp = Math.floor(Date.now() / 1000);
const data = timestamp + SECRET_KEY;
return crypto.createHash('sha256').update(data).digest('hex');
}
// 使用示例
const key = generateKey();
const url = `api.php?id=1&key=${encodeURIComponent(key)}`;
Python
import time
import hashlib
import urllib.parse
SECRET_KEY = 'tzgsc_2026_secret_key'
def generate_key():
timestamp = int(time.time())
data = str(timestamp) + SECRET_KEY
return hashlib.sha256(data.encode()).hexdigest()
# 使用示例
key = generate_key()
url = f"api.php?id=1&key={urllib.parse.quote(key)}"
Java
import java.security.MessageDigest;
import java.time.Instant;
public class KeyGenerator {
private static final String SECRET_KEY = "tzgsc_2026_secret_key";
public static String generateKey() throws Exception {
long timestamp = Instant.now().getEpochSecond();
String data = timestamp + SECRET_KEY;
MessageDigest digest = MessageDigest.getInstance("SHA-256");
byte[] hash = digest.digest(data.getBytes("UTF-8"));
StringBuilder hexString = new StringBuilder();
for (byte b : hash) {
String hex = Integer.toHexString(0xff & b);
if (hex.length() == 1) hexString.append('0');
hexString.append(hex);
}
return hexString.toString();
}
// 使用示例
public static void main(String[] args) throws Exception {
String key = generateKey();
String url = "api.php?id=1&key=" + java.net.URLEncoder.encode(key, "UTF-8");
System.out.println(url);
}
}
Go
package main
import (
"crypto/sha256"
"encoding/hex"
"fmt"
"net/url"
"time"
)
const SECRET_KEY = "tzgsc_2026_secret_key"
func generateKey() string {
timestamp := time.Now().Unix()
data := fmt.Sprintf("%d%s", timestamp, SECRET_KEY)
hash := sha256.Sum256([]byte(data))
return hex.EncodeToString(hash[:])
}
// 使用示例
func main() {
key := generateKey()
encodedKey := url.QueryEscape(key)
apiUrl := fmt.Sprintf("api.php?id=1&key=%s", encodedKey)
fmt.Println(apiUrl)
}
C#
using System;
using System.Security.Cryptography;
using System.Text;
using System.Web;
public class KeyGenerator
{
private const string SECRET_KEY = "tzgsc_2026_secret_key";
public static string GenerateKey()
{
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
string data = timestamp + SECRET_KEY;
using (SHA256 sha256 = SHA256.Create())
{
byte[] hash = sha256.ComputeHash(Encoding.UTF8.GetBytes(data));
StringBuilder builder = new StringBuilder();
foreach (byte b in hash)
{
builder.Append(b.ToString("x2"));
}
return builder.ToString();
}
}
// 使用示例
public static void Main()
{
string key = GenerateKey();
string url = $"api.php?id=1&key={HttpUtility.UrlEncode(key)}";
Console.WriteLine(url);
}
}
Ruby
require 'digest'
require 'cgi'
SECRET_KEY = 'tzgsc_2026_secret_key'
def generate_key
timestamp = Time.now.to_i
data = "#{timestamp}#{SECRET_KEY}"
Digest::SHA256.hexdigest(data)
end
# 使用示例
key = generate_key
url = "api.php?id=1&key=#{CGI.escape(key)}"
puts url
Rust
use sha2::{Sha256, Digest};
use std::time::{SystemTime, UNIX_EPOCH};
const SECRET_KEY: &str = "tzgsc_2026_secret_key";
fn generate_key() -> String {
let timestamp = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
let data = format!("{}{}", timestamp, SECRET_KEY);
let mut hasher = Sha256::new();
hasher.update(data.as_bytes());
let result = hasher.finalize();
hex::encode(result)
}
// 使用示例
fn main() {
let key = generate_key();
let encoded_key = urlencoding::encode(&key);
let url = format!("api.php?id=1&key={}", encoded_key);
println!("{}", url);
}
请求限制
| 类型 | 限制 | 说明 |
|---|---|---|
| 无 Key 请求 | 10 次/分钟 | 基于 IP 地址限制 |
| 有 Key 请求 | 无限制 | 验证通过后无频率限制 |
限制配置
define('KEY_EXPIRE_TIME', 300); // Key 有效期(秒)
define('MAX_REQUESTS_NO_KEY', 10); // 无 Key 最大请求次数
define('RATE_LIMIT_WINDOW', 60); // 限流时间窗口(秒)
接口信息
接口概述
该接口用于获取古诗文题目、验证答案、获取提示信息,支持 GET 和 POST 请求方式。
请求参数
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
| id | string/int | 是 | 题目唯一标识符 |
| msg | string | 否 | 操作类型:答案序号/提示 |
| key | string | 否 | 认证密钥(推荐携带) |
请求示例
1. 获取题目
GET p1/api.php?id=1&key=xxx
POST 请求:
POST p1/api.php
Content-Type: application/json
{
"id": "1",
"key": "xxx"
}
2. 提交答案
GET p1/api.php?id=1&msg=1&key=xxx
POST 请求:
POST p1/api.php
Content-Type: application/json
{
"id": "1",
"msg": "1",
"key": "xxx"
}
3. 获取提示
GET p1/api.php?id=1&msg=提示&key=xxx
POST 请求:
POST p1/api.php
Content-Type: application/json
{
"id": "1",
"msg": "提示",
"key": "xxx"
}
响应信息
获取题目成功响应
{
"success": true,
"new_key": "新的认证密钥",
"data": {
"id": "1",
"question": "题目内容",
"options": [
{
"num": 1,
"text": "选项1"
},
{
"num": 2,
"text": "选项2"
},
{
"num": 3,
"text": "选项3"
},
{
"num": 4,
"text": "选项4"
}
],
"author": "作者",
"type": "描写类型",
"grade": "学习阶段",
"dynasty": "年代"
}
}
答案正确响应
{
"success": true,
"type": "correct",
"message": "恭喜你,回答正确。请继续下一题",
"next_question": {
"id": "2",
"question": "下一题题目",
"options": [
...
],
"author": "作者",
"type": "描写类型",
"grade": "学习阶段",
"dynasty": "年代"
}
}
答案错误响应
{
"success": true,
"type": "wrong",
"message": "抱歉,答案不对哦。你可以回复提示获取该题的部分信息哦。"
}
提示响应
{
"success": true,
"type": "hint",
"message": "这是首描写[描写类型]的诗,你在[学习阶段]学过它。"
}
获取失败响应
{
"success": false,
"message": "抱歉,获取出现错误。"
}
错误参数响应
{
"success": false,
"message": "缺少必要参数: id"
}
不支持的请求方法
{
"success": false,
"message": "不支持的请求方法"
}
请求频率限制
{
"success": false,
"message": "请求过于频繁,请稍后再试"
}
HTTP 状态码: 429
核心功能说明
1. 题目数据来源
- 从百度汉语 API 获取题目数据
- API 地址:
https://hanyu.baidu.com/hanyu/ajax/pingce_data
2. 数据存储
- 题目数据存储在
data/tzgsc/目录 - 文件格式:
.json - 文件命名:
{id}.json - JSON 缓存:
data/tzgsc.json
3. 数据格式
题目数据存储格式 (JSON):
{
"id": "1",
"question": "题目内容",
"options": [
{"num": 1, "text": "选项1"},
{"num": 2, "text": "选项2"},
{"num": 3, "text": "选项3"},
{"num": 4, "text": "选项4"}
],
"author": "作者",
"type": "描写类型",
"grade": "学习阶段",
"dynasty": "年代",
"correct_answer": 1
}
4. 核心函数
get_question($id)
获取并返回题目
- 参数: $id - 题目 ID
- 返回: 包含题目信息的数组
submit_answer($id, $msg)
提交答案并返回结果
- 参数:
- $id - 题目 ID
- $msg - 答案序号或"提示"
- 返回: 包含答题结果的数组
cj($data)
采集并缓存题目数据
- 参数: $data - API 返回的原始数据
- 功能: 解析题目数据,去重后保存到 JSON 文件
get_curl($url, $post, $referer, $cookie, $header, $ua, $nobaody)
发送 HTTP 请求
- 参数:
- $url - 请求地址
- $post - POST 数据
- $referer - 来源地址
- $cookie - Cookie
- $header - 是否返回头部
- $ua - User-Agent
- $nobaody - 是否不返回内容
- 功能: 使用 cURL 发送 HTTP 请求,支持 SSL 和 GZIP 压缩
replace_unicode_escape_sequence($match)
Unicode 转义序列转换
- 参数: $match - 匹配到的 Unicode 序列
- 返回: UTF-8 编码的字符串
- 功能: 将 Unicode 转义序列转换为 UTF-8 字符
目录结构
p1/
├── api.php # API 接口文件
├── index.php # 前端页面(服务端生成初始 Key)
├── api.js # 前端交互脚本
└── data/
├── tzgsc.json # 题目缓存文件
├── rate_limit/ # 请求限制记录目录
└── tzgsc/
└── [id].json # 题目数据文件
注意事项
- 确保
data/tzgsc/目录具有写入权限 - API 依赖百度汉语接口,需确保网络连接正常
- 题目数据会缓存到本地,避免重复请求
- 答案验证时会读取本地保存的题目数据文件
- 支持 Unicode 编码处理和 GZIP 压缩响应
- 支持 GET 和 POST 两种请求方式
- 所有响应均为 JSON 格式