使用示例

本页面提供各种实用的代码示例,帮助您更好地使用单词记忆卡片 API。


客户端缓存策略

为了节省请求额度和提升性能,建议在客户端实现缓存机制。

// 使用 localStorage 缓存 API 响应
function getCachedOrFetch(word, lang = 'en') {
  const cacheKey = `memory-card-${word}-${lang}`
  const cached = localStorage.getItem(cacheKey)
  
  if (cached) {
    const { data, timestamp } = JSON.parse(cached)
    // 缓存 24 小时
    if (Date.now() - timestamp < 86400000) {
      console.log('使用缓存数据')
      return Promise.resolve(data)
    }
  }
  
  // 缓存未命中或已过期,请求 API
  return fetch(`https://api.keykey.cc/api/public/memory-card?word=${word}&lang=${lang}`)
    .then(res => res.json())
    .then(data => {
      // 保存到缓存
      localStorage.setItem(cacheKey, JSON.stringify({
        data,
        timestamp: Date.now()
      }))
      return data
    })
}

// 使用示例
const card = await getCachedOrFetch('hello')

批量查询单词

查询多个单词时,建议添加延迟以避免过快消耗请求配额。

// 批量查询单词,带延迟和错误处理
async function batchGetMemoryCards(words, lang = 'en', delayMs = 100) {
  const results = []
  
  for (const word of words) {
    try {
      const response = await fetch(
        `https://api.keykey.cc/api/public/memory-card?word=${encodeURIComponent(word)}&lang=${lang}`
      )
      const data = await response.json()
      
      if (data.success) {
        results.push({
          word,
          success: true,
          data: data.data,
          rateLimit: data.rateLimit
        })
      } else {
        results.push({
          word,
          success: false,
          error: data.error,
          code: data.code
        })
      }
      
      // 延迟,避免请求过快
      if (delayMs > 0) {
        await new Promise(resolve => setTimeout(resolve, delayMs))
      }
    } catch (error) {
      results.push({
        word,
        success: false,
        error: error.message
      })
    }
  }
  
  return results
}

// 使用示例
const words = ['hello', 'world', 'study', 'memory']
const results = await batchGetMemoryCards(words)

console.log(`成功: ${results.filter(r => r.success).length}`)
console.log(`失败: ${results.filter(r => !r.success).length}`)

监控 Rate Limit

通过响应头或响应体监控剩余请求次数,接近限额时提示用户。

async function getMemoryCardWithRateLimitCheck(word, lang = 'en') {
  const response = await fetch(
    `https://api.keykey.cc/api/public/memory-card?word=${word}&lang=${lang}`
  )
  
  // 从响应头获取 Rate Limit 信息
  const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0')
  const limit = parseInt(response.headers.get('X-RateLimit-Limit') || '150')
  const reset = response.headers.get('X-RateLimit-Reset')
  
  const data = await response.json()
  
  // 检查剩余次数
  if (remaining < 50) {
    console.warn(`⚠️ API 请求次数即将用尽: ${remaining}/${limit}`)
    console.warn(`将在 ${new Date(reset).toLocaleString()} 重置`)
  }
  
  if (remaining < 10) {
    alert('API 请求次数不足 10 次,请谨慎使用!')
  }
  
  return data
}

// 使用示例
const card = await getMemoryCardWithRateLimitCheck('hello')

错误处理最佳实践

完善的错误处理可以提升用户体验。

async function safeGetMemoryCard(word, lang = 'en') {
  try {
    const response = await fetch(
      `https://api.keykey.cc/api/public/memory-card?word=${word}&lang=${lang}`
    )
    const data = await response.json()
    
    // 根据不同错误码处理
    if (!data.success) {
      switch (data.code) {
        case 'NOT_FOUND':
          return {
            error: true,
            type: 'not_found',
            message: `单词 "${word}" 尚未收录`,
            suggestion: '尝试其他单词或联系管理员添加'
          }
        
        case 'RATE_LIMIT_EXCEEDED':
          const resetTime = new Date(data.rateLimit.reset)
          return {
            error: true,
            type: 'rate_limit',
            message: '请求次数已达上限',
            suggestion: `将在 ${resetTime.toLocaleString()} 重置`,
            resetTime
          }
        
        case 'INVALID_PARAMETER':
          return {
            error: true,
            type: 'invalid_input',
            message: '输入的单词格式不正确',
            suggestion: '请输入 1-100 个字符的有效单词'
          }
        
        default:
          return {
            error: true,
            type: 'unknown',
            message: data.error || '未知错误',
            suggestion: '请稍后重试'
          }
      }
    }
    
    // 成功返回
    return {
      error: false,
      data: data.data,
      rateLimit: data.rateLimit
    }
    
  } catch (error) {
    return {
      error: true,
      type: 'network',
      message: '网络请求失败',
      suggestion: '请检查网络连接',
      details: error.message
    }
  }
}

// 使用示例
const result = await safeGetMemoryCard('hello')

if (result.error) {
  console.error(`错误: ${result.message}`)
  console.log(`建议: ${result.suggestion}`)
} else {
  console.log('单词:', result.data.word)
  console.log('剩余次数:', result.rateLimit.remaining)
}

React Hook 示例

在 React 应用中使用的自定义 Hook。

import { useState, useEffect } from 'react'

function useMemoryCard(word, lang = 'en') {
  const [data, setData] = useState(null)
  const [loading, setLoading] = useState(false)
  const [error, setError] = useState(null)
  const [rateLimit, setRateLimit] = useState(null)

  useEffect(() => {
    if (!word) return

    const fetchData = async () => {
      setLoading(true)
      setError(null)

      try {
        const response = await fetch(
          `https://api.keykey.cc/api/public/memory-card?word=${encodeURIComponent(word)}&lang=${lang}`
        )
        const result = await response.json()

        if (result.success) {
          setData(result.data)
          setRateLimit(result.rateLimit)
        } else {
          setError({
            message: result.error,
            code: result.code
          })
          setRateLimit(result.rateLimit)
        }
      } catch (err) {
        setError({
          message: '网络请求失败',
          code: 'NETWORK_ERROR'
        })
      } finally {
        setLoading(false)
      }
    }

    fetchData()
  }, [word, lang])

  return { data, loading, error, rateLimit }
}

// 使用示例
function WordCard({ word }) {
  const { data, loading, error, rateLimit } = useMemoryCard(word)

  if (loading) return <div>加载中...</div>
  if (error) return <div>错误: {error.message}</div>
  if (!data) return null

  return (
    <div>
      <h2>{data.word}</h2>
      <p>{data.phonetic}</p>
      {data.examples.map((ex, i) => (
        <div key={i}>
          <p>{ex.sentence}</p>
          <p>{ex.translation}</p>
        </div>
      ))}
      <small>剩余请求: {rateLimit?.remaining}/{rateLimit?.limit}</small>
    </div>
  )
}

下一步

Was this page helpful?