# 统一请求库使用说明

统一请求库实现位置：

- `src/utils/request.ts`
- 类型定义：`src/shared/request-types.ts`

## 环境变量

必须配置：

- `VITE_API_BASE_URL`：接口基础地址（例如 `https://api.example.com`）

可选配置：

- `VITE_API_TIMEOUT_MS`：请求超时毫秒数（默认 15000）

## 上下文注入（header 来源）

请求库会在请求时自动注入以下 header（有值才注入）：

- `Authorization: Bearer <token>`（可通过 `skipAuth: true` 跳过）
- `clientId`
- `X-Latitude`
- `X-Longitude`
- `language`

你需要在业务合适时机写入上下文（内存态）：

```ts
import {
  setAuthToken,
  setClientId,
  setLocation,
  setLanguage,
} from "@/utils/request";

setClientId("your-client-id");
setAuthToken("token-string");
setLocation(30.12345, 120.12345);
setLanguage("zh-CN");
```

说明：

- `language` 如果未显式设置，会尝试从 i18n 的 `getCurrentLocale()` 获取

## 发起请求

### request<T>（兼容旧代码风格，返回 { code, message, data }）

```ts
import { request } from "@/utils/request";

const res = await request<{ records: unknown[] }>({
  method: "GET",
  url: "/xxx/list",
  params: { pageNum: 1, pageSize: 10 },
});

console.log(res.data.records);
```

### requestData<T>（推荐新代码风格，只返回 data）

```ts
import { requestData } from "@/utils/request";

const data = await requestData<{ records: unknown[] }>({
  method: "GET",
  url: "/xxx/list",
  params: { pageNum: 1, pageSize: 10 },
});

console.log(data.records);
```

### 跳过 Authorization

```ts
import { request } from "@/utils/request";

await request<string>(
  {
    method: "GET",
    url: "/public/ping",
  },
  { skipAuth: true },
);
```

### 临时追加 headers

```ts
import { request } from "@/utils/request";

await request(
  { method: "POST", url: "/xxx", data: { a: 1 } },
  { headers: { "X-Debug": "1" } },
);
```

## 错误处理（只抛错，不做 Toast）

请求失败会抛出一个 `RequestError`（符合 `NormalizedError` 结构），可根据 `kind` 分流：

- `business`：后端返回 `{ code, message, data }` 且 `code !== 0`
- `http`：HTTP 状态码错误（如 401/403/500）
- `network`：断网/超时等（无 response）
- `unknown`：返回结构不符合预期等其它情况

示例：

```ts
import type { NormalizedError } from "@/shared/request-types";
import { requestData } from "@/utils/request";

try {
  await requestData({ method: "GET", url: "/xxx" });
} catch (e) {
  const err = e as NormalizedError;
  if (err.kind === "business") {
    // err.message / err.code
  } else if (err.kind === "http") {
    // err.httpStatus
  } else if (err.kind === "network") {
    // err.message
  }
}
```

