Skip to main content

概述

本指南介绍如何在 Web 前端应用中集成 Endfield API,包括认证流程、数据获取和最佳实践。

认证策略

Web 前端推荐使用三级降级认证
JWT(已登录)→ Anonymous Token(游客)→ 无认证(公开端点)

实现参考

async function fetchAPI(endpoint, options = {}) {
  const headers = { 'Content-Type': 'application/json' };
  
  // 1. 优先使用 JWT
  const accessToken = localStorage.getItem('access_token');
  if (accessToken) {
    headers['Authorization'] = `Bearer ${accessToken}`;
  } else {
    // 2. 降级到 Anonymous Token
    let anonToken = localStorage.getItem('anonymous_token');
    if (!anonToken) {
      anonToken = await obtainAnonymousToken();
    }
    if (anonToken) {
      headers['X-Anonymous-Token'] = anonToken;
    }
  }
  
  // 3. 附加 Framework Token(如有)
  const frameworkToken = localStorage.getItem('framework_token');
  if (frameworkToken) {
    headers['X-Framework-Token'] = frameworkToken;
  }
  
  const response = await fetch(`https://api.end.shallow.ink${endpoint}`, {
    ...options,
    headers: { ...headers, ...options.headers }
  });
  
  const data = await response.json();
  
  // 处理 401:尝试刷新 Token
  if (response.status === 401 && accessToken) {
    const refreshed = await refreshAccessToken();
    if (refreshed) return fetchAPI(endpoint, options);
  }
  
  if (data.code !== 0) throw new Error(data.message);
  return data.data;
}

图片代理

森空岛 CDN 图片有防盗链限制,需要通过代理加载:
function getProxyImageUrl(imageUrl) {
  const proxyDomains = ['bbs.hycdn.cn', 'ak.hycdn.cn', 'web.hycdn.cn'];
  try {
    const url = new URL(imageUrl);
    if (proxyDomains.some(d => url.host.endsWith(d))) {
      return `https://api.end.shallow.ink/api/proxy/image?url=${encodeURIComponent(imageUrl)}`;
    }
  } catch {}
  return imageUrl;
}

常见场景

展示 Wiki 数据

// 获取干员列表
const categories = await fetchAPI('/api/wiki/categories');
const operators = await fetchAPI('/api/wiki/items?main_type_id=1&sub_type_id=1');

// 搜索
const results = await fetchAPI('/api/wiki/search?q=近卫');

展示蓝图库

// 蓝图列表(支持筛选和排序)
const blueprints = await fetchAPI('/api/blueprints?sort=-likes_count&page=1&page_size=20');

// 蓝图详情
const detail = await fetchAPI(`/api/blueprints/${blueprintId}`);

展示抽卡统计

// 全服统计(公开接口,无需认证)
const globalStats = await fetchAPI('/api/endfield/gacha/global-stats');

// 个人记录(需要 Framework Token)
const records = await fetchAPI('/api/endfield/gacha/records');