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

11 KiB
Raw Blame History

古诗文答题系统 API 文档

文件信息

  • 文件路径: p1/api.php
  • 功能描述: 古诗文题目获取与答题系统
  • 编码格式: UTF-8
  • 响应格式: JSON

安全认证

Key 认证机制

API 采用动态 Key 认证,防止接口被滥用。

认证原理

  1. 客户端生成 Key: 使用 SHA256(时间戳 + 密钥) 生成
  2. 服务端验证: 验证 Key 是否在有效期内(默认 300 秒)
  3. 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  # 题目数据文件

注意事项

  1. 确保 data/tzgsc/ 目录具有写入权限
  2. API 依赖百度汉语接口,需确保网络连接正常
  3. 题目数据会缓存到本地,避免重复请求
  4. 答案验证时会读取本地保存的题目数据文件
  5. 支持 Unicode 编码处理和 GZIP 压缩响应
  6. 支持 GET 和 POST 两种请求方式
  7. 所有响应均为 JSON 格式