---
title: "hooks"
description: "通过 Nuxt 运行时 Hook 扩展 API 系统行为，实现全局请求拦截、错误处理和 401 自定义处理。"
seo_title: "Hooks"
seo_description: "Lifecycle hooks of the Movk Nuxt API plugin — movk:api:request, movk:api:response and movk:api:error for cross-cutting logging, metrics and tracing."
canonical_url: "https://nuxt.mhaibaraai.cn/docs/api/hooks"
---
# hooks

> 通过 Nuxt 运行时 Hook 扩展 API 系统行为，实现全局请求拦截、错误处理和 401 自定义处理。

## 介绍

Movk Nuxt API 系统通过 Nuxt 运行时 Hook 暴露 4 个扩展点，可以在不修改源码的情况下扩展/定制 API 行为。

所有 Hook 类型已通过模块声明自动注册到 `RuntimeNuxtHooks`，编辑器中 `nuxtApp.hook('movk:api:')` 可获得完整自动补全。

## 可用 Hooks

### `movk:api:request`

**触发时机**: 认证 token 注入完成后，请求实际发送前。

```ts
'movk:api:request': (context: FetchContext) => void | Promise<void>
```

典型用途：添加额外请求头、请求日志、修改请求参数。

```ts [plugins/api-logger.ts]
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('movk:api:request', (context) => {
    console.log(`[API] ${context.options.method || 'GET'} ${context.request}`)
  })
})
```

### `movk:api:response`

**触发时机**: 业务状态码校验通过 + 数据解包完成后。

```ts
'movk:api:response': (
  context: FetchContext & { response: FetchResponse<any> }
) => void | Promise<void>
```

此时 `context.response._data` 已经是解包后的业务数据。

典型用途：全局数据转换、响应日志、性能分析。

```ts [plugins/api-analytics.ts]
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('movk:api:response', (context) => {
    analytics.track('api_success', {
      url: context.request,
      method: context.options.method || 'GET'
    })
  })
})
```

### `movk:api:error`

**触发时机**: 业务状态码校验失败 **或** HTTP 错误（4xx/5xx）。对于 401 错误，在 `movk:api:unauthorized` 之后触发。

```ts
'movk:api:error': (
  context: FetchContext & { response: FetchResponse<any> }
) => void | Promise<void>
```

典型用途：全局错误上报（Sentry 等）、错误分析。

```ts [plugins/error-reporter.ts]
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('movk:api:error', (context) => {
    // 上报到 Sentry（跳过已处理的 401）
    if (context.response.status !== 401) {
      Sentry.captureException(new Error(`API Error: ${context.response.status}`), {
        extra: {
          url: context.request,
          data: context.response._data
        }
      })
    }
  })
})
```

### `movk:api:unauthorized`

**触发时机**: 收到 HTTP 401 响应时，在 `movk:api:error` **之前**触发。

```ts
'movk:api:unauthorized': (
  context: FetchContext & { response: FetchResponse<any> },
  result: { handled: boolean }
) => void | Promise<void>
```

设置 `result.handled = true` 可**跳过默认的 401 处理**（清除 session + 跳转登录页）。

> \[\!WARNING\]
> 
> 如果多个处理器监听此 Hook，任一处理器设置 
> 
> result.handled = true
> 
>  即可阻止默认行为。

#### Token 刷新模式

```ts [plugins/token-refresh.ts]
export default defineNuxtPlugin((nuxtApp) => {
  let isRefreshing = false

  nuxtApp.hook('movk:api:unauthorized', async (_context, result) => {
    if (isRefreshing) return

    isRefreshing = true
    try {
      // 尝试刷新 token
      await $fetch('/api/auth/refresh', { method: 'POST' })
      // 刷新 session 状态
      const { fetch: fetchSession } = useUserSession()
      await fetchSession()
      // 标记已处理，跳过默认 401 行为
      result.handled = true
    }
    catch {
      // 刷新失败，走默认流程（清 session + 跳转登录）
    }
    finally {
      isRefreshing = false
    }
  })
})
```

## 注册方式

### 在 Nuxt 插件中（推荐）

适合全局逻辑，应用启动时自动注册：

```ts [plugins/api-hooks.ts]
export default defineNuxtPlugin((nuxtApp) => {
  nuxtApp.hook('movk:api:request', (context) => {
    // 全局请求处理
  })

  nuxtApp.hook('movk:api:error', (context) => {
    // 全局错误处理
  })
})
```

### 在组件中

适合特定页面的局部逻辑：

```vue
<script setup>
const nuxtApp = useNuxtApp()

// 仅在当前页面生效
const unregister = nuxtApp.hook('movk:api:error', (context) => {
  // 页面级别的错误处理
})

onUnmounted(() => {
  unregister() // 组件销毁时清理
})
</script>
```

> \[\!NOTE\]
> 
> 在组件中注册 Hook 时，务必通过 
> 
> onUnmounted
> 
>  调用返回的卸载函数以避免内存泄漏。

## 执行顺序

```text
请求发起
  │
  ├── 认证 token 注入
  ├── Debug 日志
  ├── movk:api:request             <-- 用户扩展点
  │
  ├── 网络请求发送 ─────────────>
  │
  ├── HTTP 2xx 响应
  │   ├── 业务成功 (code in successCodes)
  │   │   ├── 数据解包 (提取 dataKey)
  │   │   ├── movk:api:response    <-- 用户扩展点
  │   │   └── 成功 Toast
  │   │
  │   └── 业务失败
  │       ├── movk:api:error       <-- 用户扩展点
  │       ├── 错误 Toast
  │       └── throw ApiError
  │
  └── HTTP 4xx/5xx 响应
      ├── [401] movk:api:unauthorized  <-- 用户扩展点
      │       └── (未 handled) 清 session + 跳转登录
      ├── movk:api:error           <-- 用户扩展点
      └── 错误 Toast
```

## TypeScript 支持

Hook 类型已通过模块声明自动注册：

```ts [src/runtime/types/module.ts]
declare module 'nuxt/app' {
  interface RuntimeNuxtHooks {
    'movk:api:request': (context: FetchContext) => void | Promise<void>
    'movk:api:response': (context: FetchContext & { response: FetchResponse<any> }) => void | Promise<void>
    'movk:api:error': (context: FetchContext & { response: FetchResponse<any> }) => void | Promise<void>
    'movk:api:unauthorized': (
      context: FetchContext & { response: FetchResponse<any> },
      result: { handled: boolean }
    ) => void | Promise<void>
  }
}
```

无需额外配置，`nuxtApp.hook('movk:api:...')` 即可获得完整的类型推断和自动补全。


## Sitemap

See the full [sitemap](/sitemap.md) for all pages.
