---
url: https://qiwuadmin.com/backend/breakpoints.md
description: >-
  断点调试入门：在浏览器开发者工具里给电脑端前端打断点、看变量、单步执行，用 Network 面板拿到 traceId 交给后端查日志，用 Vue
  DevTools 看组件、Pinia 和路由；用 QW_INSPECT 打开后端的调试端口，在 VS Code 或 WebStorm 里给 NestJS
  服务端打断点；以及移动端 H5、小程序和 App 在哪里调试。
---

# 断点调试

**断点**是你在代码某一行做的标记。程序运行到这一行时会**暂停**，这时你可以看到每个变量当前的值，再一步一步往下执行，看程序到底走了哪条路。这种找问题的方法叫**断点调试**。

它和[排查问题](/backend/debugging)里讲的方法不一样：

| 方法 | 适合什么 |
| --- | --- |
| 看日志、按 traceId 搜索 | 事后回看：请求已经结束了，看它留下的记录 |
| 断点调试 | 现场观察：让程序停在某一行，直接看变量的值 |

两种方法经常一起用：先用 traceId 和日志确定问题大概在哪里，再到那里打断点细看。

## 前端（电脑端）

### 准备

在仓库根目录运行 `pnpm dev`（macOS 和 Windows 命令相同），然后按终端打印的前端地址在浏览器里打开，默认是 `http://localhost:5173`。

开发模式下，前端由 **Vite**（前端的开发服务器和构建工具）提供。浏览器实际运行的是编译后的代码，但 Vite 会同时提供 **source map**（源码映射：记录编译后的代码对应源码的哪一行），所以在开发者工具里看到和打断点的，都是你写的 `.vue` 和 `.ts` 原文件。

### 打开开发者工具

推荐用 Edge 或 Chrome，两者的开发者工具是一样的。

| 系统 | 快捷键 |
| --- | --- |
| Windows | `F12` 或 `Ctrl + Shift + I` |
| macOS | `Cmd + Option + I` |

也可以在页面上点右键，选**检查**。

### 在 Sources 面板里打断点

1. 切换到 **Sources**（源代码）面板；
2. 按 `Ctrl + P`（macOS 是 `Cmd + P`），输入文件名，比如 `position`，从列表里选中要看的文件；
3. 点击代码左边的**行号**，行号上出现一个蓝色标记，断点就打好了。再点一次是取消；
4. 在页面上做一次会执行到这一行的操作，比如点**搜索**按钮。程序停下来，这一行被高亮。

程序暂停后，右侧可以看到：

* **Scope**（作用域）：当前能访问到的所有变量和它们的值；
* **Watch**（监视）：点 `+` 输入一个变量名或表达式，比如 `form.name`，它的值会一直显示在这里；
* **Call Stack**（调用栈）：程序是经过哪些函数一层层调用到这里的。

把鼠标停在代码里的变量上，也能直接看到它的值。

用面板上方的按钮（或快捷键）控制执行：

| 按钮 | 快捷键 | 作用 |
| --- | --- | --- |
| 继续 | `F8` | 一直运行到下一个断点 |
| 单步跳过 | `F10` | 执行当前这一行，停在下一行；遇到函数调用不进去 |
| 单步进入 | `F11` | 遇到函数调用时，进到函数里面 |
| 单步跳出 | `Shift + F11` | 执行完当前函数，回到调用它的地方 |

### 用代码打断点：`debugger`

在代码里写一行 `debugger`，开发者工具打开时，程序运行到这里就会暂停，效果和点行号一样：

```ts
function onSubmit() {
  debugger // 运行到这里暂停
  // …
}
```

找不到文件、或者代码在很深的地方时，这样更方便。

::: warning 用完一定要删掉
`debugger` 只用于本地调试，不能提交。电脑端的代码检查会把它当成错误：`pnpm lint`（`pnpm verify` 的第一项）会报 `no-debugger`，检查不通过。
:::

### 在 Network 面板里看请求

**Network**（网络）面板列出页面发出的所有请求。点一个请求，可以看到：

* **Headers**（请求头和响应头）：请求地址、方法、状态码，以及响应头里的 `X-Request-Id`；
* **Payload**（请求参数）：前端发出去的数据；
* **Response**（响应内容）：后端返回的数据。

本项目的接口都用统一的格式返回：

```json
{ "code": 0, "msg": "ok", "data": { "…": "…" } }
```

`code` 是 `0` 表示成功，数据在 `data` 里。出错时返回的是错误码、翻译好的错误信息和请求编号：

```json
{ "code": "…", "msg": "…", "traceId": "6f1c…" }
```

**traceId**（请求编号）就是每个请求的编号，和响应头 `X-Request-Id` 的值相同。前端的问题查到最后发现是后端返回了错误时，把 traceId 复制下来，到服务端日志里搜索，方法见[排查问题](/backend/debugging#先看-traceid)。

::: tip 先分清是前端还是后端的问题
在 Network 面板里看一眼响应：后端返回的数据是对的、页面显示错了，是前端的问题，在前端打断点；后端返回的就是错的，再去查后端。
:::

### Console 面板

**Console**（控制台）面板显示前端的报错和 `console.log` 的输出。页面不正常时先看这里有没有红色的报错，点报错右边的文件名可以跳到出错的那一行。

程序停在断点上时，也可以在 Console 里直接输入变量名或表达式，看它的值。

### Vue DevTools

**Vue DevTools** 是 Vue 官方的浏览器扩展，在 Chrome 应用商店或 Edge 加载项商店里搜索 **Vue.js devtools** 安装。安装后，开发者工具里会多出一个 **Vue** 面板，可以看到：

* **组件树**：页面由哪些组件组成，每个组件的 props 和状态；
* **Pinia**：本项目用 Pinia 管理全局状态（比如 `auth` 存当前登录用户和权限），可以直接看到每个 store 里的数据；
* **路由**：当前路由和所有已注册的路由。

Vue DevTools 只在 `pnpm dev` 的开发模式下可用，构建后的正式版本看不到。

也可以在 VS Code 里调试前端：仓库自带两个调试配置 **Web: Edge (Vite dev server)** 和 **Web: Chrome (Vite dev server)**（在 `.vscode/launch.json` 里）。`pnpm dev` 运行时，在 VS Code 的**运行和调试**里选其中一个，它会打开一个可调试的浏览器并访问 `http://localhost:5173`，断点直接打在 VS Code 里 `apps/web/src` 的文件上。这不是必需的，用浏览器自带的开发者工具效果一样。

## 手机端

移动端有三种运行方式，调试工具各不相同。怎么启动它们，见[移动端开发](/core/mobile#安装与运行)。

| 平台 | 在哪里调试 |
| --- | --- |
| H5 | 浏览器开发者工具，和上面电脑端的方法完全一样。点开发者工具左上角的**设备工具栏**图标（`Ctrl + Shift + M`，macOS 是 `Cmd + Shift + M`），把页面切换成手机尺寸 |
| 微信小程序 | 运行 `pnpm -C mobile dev:mp-weixin`，在**微信开发者工具**里导入 `mobile/dist/dev/mp-weixin`。它自带调试器，也有 Console、Sources、Network 面板，用法和浏览器差不多 |
| App | 运行 `pnpm -C mobile dev:app`，在 **HBuilderX** 里导入 `mobile/dist/dev/app`，运行到手机或模拟器。App 打印的日志和报错显示在 HBuilderX 下方的控制台里 |

日常写页面优先用 H5 调试，最方便；小程序和 App 用来核对只在那个平台上才有的问题。

## 后端

后端（NestJS 服务端）也能像前端一样打断点：程序停在某一行，在编辑器里看变量、单步执行。做法是让后端进程打开 Node.js 的**调试端口**（inspector：调试器通过这个端口连上正在运行的 Node 进程），再用 VS Code 或 WebStorm **附加**（attach）上去。“附加”的意思是：程序已经在运行，调试器连上去，而不是由调试器重新启动程序。

### 第一步：带调试端口启动开发服务

平时用 `pnpm dev` 启动开发服务。要调试后端时，改成在启动前设置环境变量 `QW_INSPECT=1`：

::: code-group

```bash [macOS]
QW_INSPECT=1 pnpm dev
```

```powershell [Windows（PowerShell）]
$env:QW_INSPECT=1; pnpm.cmd dev
```

:::

PowerShell 的设置会保留在当前终端里，之后再在这个终端运行 `pnpm dev` 也会带上调试端口。不需要时用 `Remove-Item Env:QW_INSPECT` 清除，或者关闭这个终端。

用 Windows 的 cmd（命令提示符）时，先运行 `set "QW_INSPECT=1"`，再运行 `call pnpm.cmd dev`；用完运行 `set "QW_INSPECT="` 清除。

这样启动后：

* 只有**后端应用进程**打开调试端口，地址是 `127.0.0.1:9229`。`pnpm dev` 里同时运行的 TypeScript 编译（tsc）和前端的 Vite 不受影响；
* 端口只监听本机（`127.0.0.1`），局域网里的其他电脑连不上；
* 同时打开了 **source map**（源码映射），所以断点可以直接打在 TypeScript 源文件上，不用去看编译后的 JavaScript。

`QW_INSPECT` 可以取这些值：

| 值 | 效果 |
| --- | --- |
| `1` 或 `true` | 打开调试端口 `9229` |
| 1024 到 65535 之间的端口号，比如 `9230` | 换成这个端口。这时要把 `.vscode/launch.json` 里后端配置的 `port` 改成相同的值 |
| `0`、`false` 或不设置 | 不打开调试端口，和平时的 `pnpm dev` 一样 |
| 其他值 | 终端里打印一条警告，然后忽略，不打开调试端口 |

`9229` 被别的程序占用时（比如另一个项目也在调试），就换一个端口号。

::: warning 不要用全局的 NODE_OPTIONS=--inspect
网上常见的做法是设置 `NODE_OPTIONS=--inspect`。在本项目里不要这样做：`pnpm dev` 会启动好几个 Node 进程（tsc、后端、Vite……），每个进程都会去抢同一个调试端口。用 `QW_INSPECT`，只有后端应用进程打开调试端口。
:::

### 第二步：在 VS Code 里附加

仓库里提交了 VS Code 的调试配置文件 `.vscode/launch.json`，不用自己写。

1. 用 VS Code 打开仓库根目录；
2. 确认第一步的 `pnpm dev` 正在运行，终端里后端已经启动；
3. 点左侧栏的**运行和调试**（Run and Debug，快捷键 `Ctrl + Shift + D`，macOS 是 `Cmd + Shift + D`）；
4. 在顶部的下拉框里选 **Server: attach (pnpm dev with QW_INSPECT=1)**，点旁边的绿色三角形开始。连上后，VS Code 底部的状态栏会变色；
5. 打开 `apps/server/src`（后端代码）或 `packages/shared/src`（前后端共用的代码）里的 `.ts` 文件，点行号左边打断点，出现红点就打好了；
6. 到浏览器的页面上做一次会调用这段代码的操作，比如在列表页点**搜索**，让前端发出请求；
7. 程序停在断点上。左侧可以看到**变量**（Variables）、**监视**（Watch）和**调用堆栈**（Call Stack），把鼠标停在代码里的变量上也能看到它的值。

控制执行的按钮在编辑器顶部的调试工具栏上，快捷键和浏览器开发者工具差不多：

| 按钮 | 快捷键 | 作用 |
| --- | --- | --- |
| 继续 | `F5` | 一直运行到下一个断点 |
| 单步跳过 | `F10` | 执行当前这一行，停在下一行；遇到函数调用不进去 |
| 单步进入 | `F11` | 遇到函数调用时，进到函数里面 |
| 单步跳出 | `Shift + F11` | 执行完当前函数，回到调用它的地方 |
| 断开 | `Shift + F5` | 断开调试器，后端继续运行 |

::: tip 程序停在断点上时，请求在等待
后端停在断点上的这段时间，这个请求一直没有返回，页面会一直转圈。停太久，前端可能显示请求超时，这是正常的，按**继续**让程序跑完就好。
:::

### 改代码后自动重新附加

开发模式下，保存后端的代码文件后，后端会自动重新编译并重启。重启后调试端口不变，VS Code 的这个配置会**自动重新附加**，断点也还在，不用再点一次开始。

要注意的是**启动阶段的代码**，比如模块初始化（`onModuleInit`）和应用启动入口（bootstrap）。后端重启时，这些代码在调试器重新附加之前就已经执行完了，所以第一次附加时断不到。办法是：先附加上，再修改并保存一次后端的文件（比如加一个空行）触发重启，这时调试器已经在等待，就能停在启动阶段的断点上。

### WebStorm

WebStorm（以及其他 JetBrains 编辑器）没有使用 `.vscode/launch.json`。新建一个 **Attach to Node.js/Chrome** 类型的运行配置，主机填 `127.0.0.1`，端口填 `9229`（或你在 `QW_INSPECT` 里写的端口），勾选重新连接（Reconnect automatically），然后以调试方式运行这个配置即可。断点同样打在 TypeScript 源文件上。

仓库里的说明见[快速开始 · 断点调试](https://github.com/732124645/qiwu-vue-admin/blob/main/docs/getting-started.md#断点调试)。断点调试从 1.3.1 版开始提供；更早的版本请用 traceId 加日志、用 Swagger 直接调接口来排查，方法见[排查问题](/backend/debugging)。
