> ## Documentation Index
> Fetch the complete documentation index at: https://end-docs.shallow.ink/llms.txt
> Use this file to discover all available pages before exploring further.

# Web 前端集成

> 在你的 Web 应用中集成 Endfield API，实现游戏数据展示。

## 概述

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

## 认证策略

Web 前端推荐使用**三级降级认证**：

```
JWT（已登录）→ Anonymous Token（游客）→ 无认证（公开端点）
```

### 实现参考

```javascript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
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 图片有防盗链限制，需要通过代理加载：

```javascript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
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 数据

```javascript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
// 获取干员列表
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=近卫');
```

### 展示蓝图库

```javascript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
// 蓝图列表（支持筛选和排序）
const blueprints = await fetchAPI('/api/blueprints?sort=-likes_count&page=1&page_size=20');

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

### 展示抽卡统计

```javascript theme={"theme":{"light":"github-light","dark":"vitesse-dark"}}
// 全服统计（公开接口，无需认证）
const globalStats = await fetchAPI('/api/endfield/gacha/global-stats');

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