npm package: @kwayteow/http
Description: 一个实用的 TypeScript 工具函数库，提供了常用的工具函数集合。
Author: kway-teow
Latest version: 0.1.0

# @kway-teow/http

一个实用的 TypeScript 工具函数库，提供了常用的工具函数集合。

## 安装

```bash
npm install @kway-teow/http
# 或者
yarn add @kway-teow/http
# 或者
pnpm add @kway-teow/http
```

## 使用

### HTTP 工具类

```typescript
import { Http } from '@kway-teow/http'

// 创建 HTTP 实例
const http = new Http('https://api.example.com')

// 发送 GET 请求
const response = await http.get('/users')
```

## 开发要求

- Node.js >= 22
- pnpm >= 10

## 开发命令

```bash
# 安装依赖
pnpm install

# 开发模式
pnpm dev

# 运行测试
pnpm test

# 生成测试覆盖率报告
pnpm coverage

# 生成文档
pnpm typedoc

# 监听文档变化
pnpm typedoc:dev

# 构建项目
pnpm build

# 代码提交
pnpm cz

# 发布新版本
pnpm release
```

## 文档

API 文档提供了详细的函数和类的使用说明：

### Http 类

主要的 HTTP 客户端类，基于 ky 实现，支持并发控制、自动 JSON 解析等功能。

```typescript
import { Http } from '@kwayteow/http'

// 基本用法
const http = new Http({
  baseUrl: 'https://api.example.com',
  concurrency: {
    maxConcurrent: 5,  // 最大并发请求数
    maxQueue: 100,     // 队列最大长度
    timeout: 30000     // 超时时间(ms)
  }
})

// HTTP 方法
const users = await http.get<User[]>('/users')
const user = await http.post<User>('/users', { json: { name: 'John' } })
const updatedUser = await http.put<User>('/users/1', { json: { name: 'John Doe' } })
const patchedUser = await http.patch<User>('/users/1', { json: { name: 'John Doe' } })
await http.delete('/users/1')
const response = await http.head('/users')

// 并发控制信息
const currentConcurrent = http.getCurrentConcurrent() // 获取当前并发请求数
const queueLength = http.getQueueLength()             // 获取当前等待队列长度
http.clearQueue()                                     // 清空请求队列
```

### 常见问题

#### 如何设置全局请求头？

可以在创建 Http 实例时通过 headers 选项设置全局请求头：

```typescript
const http = new Http({
  baseUrl: 'https://api.example.com',
  headers: {
    'Authorization': 'Bearer your-token',
    'Content-Type': 'application/json'
  }
})
```

#### 如何处理请求错误？

所有请求方法都返回 Promise，可以使用 try/catch 或者 .catch() 处理错误：

```typescript
try {
  const data = await http.get<User[]>('/users')
  // 处理成功响应
} catch (error) {
  // 处理错误
  console.error('请求失败:', error.message)
}
```

#### 如何设置请求超时？

可以在创建 Http 实例时设置默认超时时间，或者在单个请求中设置：

```typescript
// 全局超时设置
const http = new Http({
  timeout: 5000 // 5秒
})

// 单个请求超时设置
const data = await http.get('/slow-endpoint', { 
  timeout: 10000 // 10秒
})
```

#### 如何取消请求？

可以使用 AbortController 取消请求：

```typescript
const controller = new AbortController()
const { signal } = controller

// 传递 signal 到请求选项
http.get('/users', { signal })

// 取消请求
setTimeout(() => controller.abort(), 1000) // 1秒后取消
```


### 高级用法

#### 文件上传

```typescript
const formData = new FormData()
formData.append('file', fileInput.files[0])
formData.append('name', 'profile-picture')

const response = await http.post('/upload', {
  body: formData
})
```

#### 请求拦截器

可以通过创建自定义的 ky 实例来实现请求拦截：

```typescript
import ky from 'ky'
import { Http } from '@kwayteow/http'

// 创建自定义 ky 实例
const customKy = ky.extend({
  hooks: {
    beforeRequest: [
      request => {
        // 添加自定义逻辑，如添加动态 token
        const token = getTokenFromSomewhere()
        request.headers.set('Authorization', `Bearer ${token}`)
      }
    ],
    afterResponse: [
      async (request, options, response) => {
        // 响应处理，例如刷新 token
        if (response.status === 401) {
          // 尝试刷新 token
          await refreshToken()
          // 返回新的请求实例重试
          return ky(request)
        }
      }
    ]
  }
})

// 使用自定义 ky 实例创建 Http 实例
const http = new Http({
  baseUrl: 'https://api.example.com',
  _instance: customKy // 传递自定义 ky 实例
})
```

#### 批量请求处理

结合并发控制进行批量请求处理：

```typescript
// 假设我们有一个大型 ID 列表需要获取详情
const ids = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

// 使用 Promise.all 和并发控制
const http = new Http({
  concurrency: {
    maxConcurrent: 3 // 最多同时发送3个请求
  }
})

// 获取所有用户数据
const users = await Promise.all(
  ids.map(id => http.get(`/users/${id}`))
)
```


### 实际使用场景

#### 图片库应用

在开发一个图片库应用时，可能需要同时加载多张图片缩略图，但又不希望一次性发送过多请求。使用 @kwayteow/http 可以轻松控制并发请求数：

```typescript
import { Http } from '@kwayteow/http'

// 创建一个限制并发的HTTP客户端
const http = new Http({
  concurrency: { maxConcurrent: 4 } // 同时最多加载4张图片
})

// 图片ID列表
const imageIds = ['img1', 'img2', 'img3', ..., 'img100']

// 获取所有图片的缩略图
async function loadThumbnails() {
  const thumbnailElements = []
  
  for (const id of imageIds) {
    try {
      // 这些请求会自动排队，最多同时执行4个
      const response = await http.get(`/images/${id}/thumbnail`)
      const imgUrl = URL.createObjectURL(response)
      
      // 创建图片元素
      const img = document.createElement('img')
      img.src = imgUrl
      thumbnailElements.push(img)
    } catch (error) {
      console.error(`加载图片 ${id} 失败`, error)
    }
  }
  
  return thumbnailElements
}

// 使用方式
const galleryElement = document.getElementById('gallery')
loadThumbnails().then(thumbnails => {
  thumbnails.forEach(thumb => {
    galleryElement.appendChild(thumb)
  })
})
```

#### 数据仪表盘

在开发一个数据仪表盘，需要从多个API端点获取数据时：

```typescript
import { Http } from '@kwayteow/http'

// 创建HTTP客户端
const http = new Http({
  baseUrl: 'https://api.example.com',
  timeout: 10000, // 10秒超时
  retry: 2 // 失败时自动重试2次
})

// 仪表盘数据加载
async function loadDashboardData() {
  try {
    // 并行获取多个数据源，自动处理并发控制
    const [userStats, salesData, performanceMetrics] = await Promise.all([
      http.get('/users/stats'),
      http.get('/sales/monthly'),
      http.get('/performance/metrics')
    ])
    
    // 使用获取的数据更新UI
    updateUserStatsChart(userStats)
    updateSalesChart(salesData)
    updatePerformanceIndicators(performanceMetrics)
    
    // 标记加载完成
    setLoading(false)
  } catch (error) {
    // 显示错误信息
    showErrorNotification('加载仪表盘数据失败', error.message)
  }
}
```


### 详细文档

更详细的API文档可通过以下方式生成：

```bash
pnpm typedoc
```

生成的文档将位于 `docs` 目录下，可以通过浏览器打开 `docs/index.html` 查看。

## 特性

- 使用 TypeScript 编写，提供完整的类型定义
- 100% 测试覆盖率
- 完整的 API 文档
- 支持 ESM 和 CommonJS

## License

MIT