Skip to content

Cursor 编辑器完整教程

目录

  1. Cursor简介与核心优势
  2. 安装与配置
  3. Cmd+K 内联编辑
  4. Chat 智能对话
  5. Composer 多文件编辑
  6. 与GitHub Copilot对比
  7. 高级技巧与工作流
  8. 实战项目案例

Cursor简介与核心优势

什么是 Cursor

Cursor 是一款基于 VS Code 深度分叉(fork)的 AI 原生代码编辑器。它不是简单地在 编辑器上叠加 AI 插件,而是将 AI 能力深度融入编辑器的每一个交互环节。Cursor 支持 GPT-4、Claude 等多种大模型,提供了代码补全、内联编辑(Cmd+K)、智能对话(Chat)、 多文件编辑(Composer)等核心功能。

核心架构

┌─────────────────────────────────────────────────────────────────┐
│                    Cursor 编辑器架构                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                     用户界面层                              │  │
│  │  ┌──────────┐  ┌──────────┐  ┌──────────┐  ┌──────────┐  │  │
│  │  │ 代码编辑  │  │ Cmd+K    │  │ Chat     │  │ Composer │  │  │
│  │  │ (补全)    │  │ (内联)   │  │ (对话)   │  │ (多文件) │  │  │
│  │  └────┬─────┘  └────┬─────┘  └────┬─────┘  └────┬─────┘  │  │
│  └───────┼──────────────┼──────────────┼──────────────┼───────┘  │
│          v              v              v              v          │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                   AI 引擎层                                │  │
│  │  ┌──────────────────────────────────────────────────────┐ │  │
│  │  │  上下文引擎                                          │ │  │
│  │  │  - 代码库索引 (全项目语义搜索)                        │ │  │
│  │  │  - 打开文件分析                                      │ │  │
│  │  │  - Git 历史追踪                                      │ │  │
│  │  │  - 符号/引用解析                                     │ │  │
│  │  └──────────────────────────────────────────────────────┘ │  │
│  │  ┌──────────────────────────────────────────────────────┐ │  │
│  │  │  模型路由                                            │ │  │
│  │  │  ┌──────────┐  ┌──────────┐  ┌──────────────────┐  │ │  │
│  │  │  │ GPT-4o   │  │ Claude   │  │ cursor-small     │  │ │  │
│  │  │  │ (对话)   │  │ (编辑)   │  │ (快速补全)       │  │ │  │
│  │  │  └──────────┘  └──────────┘  └──────────────────┘  │ │  │
│  │  └──────────────────────────────────────────────────────┘ │  │
│  └───────────────────────────────────────────────────────────┘  │
│                                                                 │
│  ┌───────────────────────────────────────────────────────────┐  │
│  │                   VS Code 基础层                           │  │
│  │  扩展系统 | 文件系统 | 终端 | 调试器 | Git 集成             │  │
│  └───────────────────────────────────────────────────────────┘  │
└─────────────────────────────────────────────────────────────────┘

Cursor 三大核心功能

┌────────────────────────────────────────────────────────────────┐
│                 Cursor 三大核心功能对比                          │
├──────────────┬──────────────┬──────────────┬──────────────────┤
│  维度         │  Cmd+K       │  Chat        │  Composer        │
├──────────────┼──────────────┼──────────────┼──────────────────┤
│  触发方式     │  Ctrl+K      │  Ctrl+L      │  Ctrl+Shift+I   │
│  操作范围     │  选中代码/    │  整个项目     │  多个文件        │
│              │  当前位置     │              │                  │
│  交互模式     │  单次指令     │  多轮对话     │  任务式编排      │
│  适用场景     │  局部修改     │  问答/分析    │  跨文件重构      │
│  上下文       │  当前文件     │  @引用       │  自动检测        │
│  输出方式     │  原地替换     │  侧边面板     │  diff 预览       │
├──────────────┴──────────────┴──────────────┴──────────────────┤
│  使用频率建议:                                                 │
│  Cmd+K (60%) > Chat (25%) > Composer (15%)                    │
│  日常小修改用Cmd+K, 问问题用Chat, 大改动用Composer              │
└────────────────────────────────────────────────────────────────┘

安装与配置

安装流程

┌──────────────────────────────────────────────────────────────┐
│                  Cursor 安装配置流程                           │
├──────────────────────────────────────────────────────────────┤
│                                                              │
│  Step 1: 下载安装                                            │
│  ┌────────────────────────────────────┐                      │
│  │  访问 cursor.com                   │                      │
│  │  下载对应平台安装包                 │                      │
│  │  (Windows / macOS / Linux)         │                      │
│  └──────────────┬─────────────────────┘                      │
│                 v                                             │
│  Step 2: 迁移 VS Code 配置                                   │
│  ┌────────────────────────────────────┐                      │
│  │  首次启动时会提示:                  │                      │
│  │  - 导入 VS Code 扩展               │                      │
│  │  - 导入 VS Code 设置               │                      │
│  │  - 导入 VS Code 快捷键             │                      │
│  │  建议: 全部导入, 无缝切换           │                      │
│  └──────────────┬─────────────────────┘                      │
│                 v                                             │
│  Step 3: 登录 Cursor 账号                                    │
│  ┌────────────────────────────────────┐                      │
│  │  支持: GitHub / Google / Email     │                      │
│  │  免费版: 每月 2000 次补全           │                      │
│  │  Pro版:  $20/月, 无限补全+GPT-4    │                      │
│  └──────────────┬─────────────────────┘                      │
│                 v                                             │
│  Step 4: 配置 AI 模型偏好                                    │
│  ┌────────────────────────────────────┐                      │
│  │  Settings > Models                 │                      │
│  │  选择默认模型 (GPT-4o / Claude)    │                      │
│  │  可以按功能分别设置模型             │                      │
│  └────────────────────────────────────┘                      │
│                                                              │
└──────────────────────────────────────────────────────────────┘

核心设置推荐

json
// Cursor Settings (settings.json)
{
    // ===== AI 功能配置 =====

    // 开启代码库索引(让AI理解整个项目)
    "cursor.codebaseIndexing.enabled": true,

    // Tab 补全行为
    "cursor.autocomplete.enabled": true,
    "cursor.autocomplete.alwaysSuggest": true,

    // 自动导入建议
    "cursor.autocomplete.autoImport": true,

    // ===== 编辑器优化 =====

    // 内联建议样式
    "editor.inlineSuggest.enabled": true,
    "editor.suggest.preview": true,

    // 保存时自动格式化
    "editor.formatOnSave": true,

    // ===== 模型选择 =====
    // 可在 Cursor Settings > Models 中配置
    // 推荐:
    //   Chat: claude-3.5-sonnet (推理更强)
    //   Edit: gpt-4o (编辑更快)
    //   Autocomplete: cursor-small (速度优先)

    // ===== 隐私设置 =====
    // 隐私模式: 代码不会被用于训练
    "cursor.privacy.mode": "privacy"
}

快捷键体系

┌────────────────────────────────────────────────────────────────┐
│              Cursor 快捷键完整速查表                             │
├────────────────────┬───────────────────────────────────────────┤
│  功能               │  快捷键 (Win/Linux)                       │
├────────────────────┼───────────────────────────────────────────┤
│                    │  === AI 核心功能 ===                       │
│  Cmd+K 内联编辑     │  Ctrl + K                                 │
│  Chat 对话面板      │  Ctrl + L                                 │
│  Composer 多文件    │  Ctrl + Shift + I                         │
│  接受 AI 建议       │  Tab                                      │
│  拒绝 AI 建议       │  Esc                                      │
│  查看下一个建议      │  Alt + ]                                  │
│                    │                                            │
│                    │  === Chat 操作 ===                         │
│  新建 Chat          │  Ctrl + L (无选中代码时)                   │
│  添加代码到 Chat     │  选中代码后 Ctrl + L                      │
│  添加文件到 Chat     │  在Chat中输入 @file                       │
│  添加文档到 Chat     │  在Chat中输入 @doc                        │
│  添加代码库到 Chat   │  在Chat中输入 @codebase                   │
│                    │                                            │
│                    │  === 编辑器标准 ===                        │
│  命令面板           │  Ctrl + Shift + P                          │
│  文件搜索           │  Ctrl + P                                  │
│  全局搜索           │  Ctrl + Shift + F                          │
│  终端切换           │  Ctrl + `                                  │
├────────────────────┴───────────────────────────────────────────┤
│  提示: macOS 用户将 Ctrl 替换为 Cmd                             │
└────────────────────────────────────────────────────────────────┘

Cmd+K 内联编辑

工作原理

Cmd+K(Windows 上为 Ctrl+K)是 Cursor 最高频使用的功能。它允许你在编辑器内直接 用自然语言描述你想要的修改,AI 会在原位生成或替换代码。

┌────────────────────────────────────────────────────────────────┐
│                  Cmd+K 工作流程                                 │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  模式A: 无选中代码 (生成新代码)                                 │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  1. 将光标放在想插入代码的位置                            │  │
│  │  2. 按 Ctrl+K                                            │  │
│  │  3. 输入指令: "创建一个用户注册的Express路由"              │  │
│  │  4. AI 在光标位置生成代码                                 │  │
│  │  5. 按 Tab 接受 / Esc 拒绝                               │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                │
│  模式B: 有选中代码 (修改现有代码)                               │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  1. 选中要修改的代码块                                    │  │
│  │  2. 按 Ctrl+K                                            │  │
│  │  3. 输入指令: "添加错误处理和输入验证"                     │  │
│  │  4. AI 显示 diff 对比(红色删除/绿色新增)                  │  │
│  │  5. 按 Tab 接受 / Esc 拒绝                               │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                │
│  模式C: 终端中使用 (生成命令)                                   │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  1. 在终端中按 Ctrl+K                                    │  │
│  │  2. 输入: "查找所有大于100MB的日志文件并删除"              │  │
│  │  3. AI 生成对应的 shell 命令                              │  │
│  │  4. 按 Enter 执行                                        │  │
│  └──────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────┘

Cmd+K 实战示例

python
# ============================================================
# 示例1: 生成新代码
# 光标放在这里, 按 Ctrl+K, 输入:
# "创建一个FastAPI路由, 实现用户CRUD, 包含分页和搜索"
# ============================================================

from fastapi import FastAPI, HTTPException, Query
from pydantic import BaseModel, EmailStr
from typing import Optional, List
from datetime import datetime

app = FastAPI(title="用户管理API")

# 用户数据模型
class UserCreate(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None

class UserResponse(BaseModel):
    id: int
    username: str
    email: str
    full_name: Optional[str]
    created_at: datetime
    is_active: bool

class UserUpdate(BaseModel):
    email: Optional[EmailStr] = None
    full_name: Optional[str] = None
    is_active: Optional[bool] = None

# 模拟数据库
users_db: dict = {}
next_id = 1


# 创建用户
@app.post("/users", response_model=UserResponse, status_code=201)
async def create_user(user: UserCreate):
    global next_id

    # 检查用户名是否已存在
    for existing in users_db.values():
        if existing["username"] == user.username:
            raise HTTPException(status_code=409, detail="用户名已存在")

    user_data = {
        "id": next_id,
        "username": user.username,
        "email": user.email,
        "full_name": user.full_name,
        "created_at": datetime.now(),
        "is_active": True
    }
    users_db[next_id] = user_data
    next_id += 1
    return user_data


# 获取用户列表(支持分页和搜索)
@app.get("/users", response_model=List[UserResponse])
async def list_users(
    page: int = Query(1, ge=1, description="页码"),
    size: int = Query(10, ge=1, le=100, description="每页数量"),
    search: Optional[str] = Query(None, description="搜索关键词")
):
    all_users = list(users_db.values())

    # 搜索过滤
    if search:
        all_users = [
            u for u in all_users
            if search.lower() in u["username"].lower()
            or search.lower() in (u.get("full_name") or "").lower()
        ]

    # 分页
    start = (page - 1) * size
    end = start + size
    return all_users[start:end]


# 获取单个用户
@app.get("/users/{user_id}", response_model=UserResponse)
async def get_user(user_id: int):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="用户不存在")
    return users_db[user_id]


# 更新用户
@app.patch("/users/{user_id}", response_model=UserResponse)
async def update_user(user_id: int, user_update: UserUpdate):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="用户不存在")

    user_data = users_db[user_id]
    update_dict = user_update.dict(exclude_unset=True)
    user_data.update(update_dict)
    return user_data


# 删除用户
@app.delete("/users/{user_id}", status_code=204)
async def delete_user(user_id: int):
    if user_id not in users_db:
        raise HTTPException(status_code=404, detail="用户不存在")
    del users_db[user_id]
python
# ============================================================
# 示例2: 选中代码后用 Cmd+K 重构
# 选中下面的函数, 按 Ctrl+K, 输入:
# "重构为async, 添加超时控制和重试逻辑"
# ============================================================

import asyncio
import aiohttp
from typing import Optional

# 重构前的简单版本:
def fetch_data_simple(url: str) -> dict:
    import requests
    response = requests.get(url)
    return response.json()


# Cmd+K 重构后的完整版本:
async def fetch_data(
    url: str,
    timeout: int = 30,
    max_retries: int = 3,
    retry_delay: float = 1.0
) -> Optional[dict]:
    """
    异步获取远程数据,支持超时和重试。

    Args:
        url: 请求URL
        timeout: 超时时间(秒)
        max_retries: 最大重试次数
        retry_delay: 重试间隔(秒), 每次翻倍

    Returns:
        JSON响应数据, 失败返回None
    """
    for attempt in range(max_retries):
        try:
            async with aiohttp.ClientSession() as session:
                async with session.get(
                    url,
                    timeout=aiohttp.ClientTimeout(total=timeout)
                ) as response:
                    if response.status == 200:
                        return await response.json()
                    elif response.status >= 500:
                        # 服务端错误,可以重试
                        raise aiohttp.ClientError(f"服务端错误: {response.status}")
                    else:
                        # 客户端错误,不重试
                        print(f"请求失败: HTTP {response.status}")
                        return None

        except (aiohttp.ClientError, asyncio.TimeoutError) as e:
            if attempt < max_retries - 1:
                wait_time = retry_delay * (2 ** attempt)
                print(f"第{attempt + 1}次请求失败, {wait_time}秒后重试: {e}")
                await asyncio.sleep(wait_time)
            else:
                print(f"所有{max_retries}次请求均失败: {e}")
                return None

    return None

Chat 智能对话

Chat 功能详解

┌────────────────────────────────────────────────────────────────┐
│                  Cursor Chat 功能架构                           │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                  上下文引用系统                            │  │
│  │                                                          │  │
│  │  @file        引用指定文件                                │  │
│  │  @folder      引用整个文件夹                              │  │
│  │  @codebase    搜索整个代码库 (语义搜索)                   │  │
│  │  @doc         引用外部文档 URL                            │  │
│  │  @git         引用 Git 变更记录                           │  │
│  │  @web         联网搜索最新信息                             │  │
│  │  @definitions 引用符号定义                                │  │
│  │  选中代码      自动作为上下文                              │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                  Chat 使用场景                             │  │
│  │                                                          │  │
│  │  [1] 代码理解    "解释这个函数的作用和潜在问题"            │  │
│  │  [2] Bug 排查    "这段代码为什么输出和预期不一致?"         │  │
│  │  [3] 方案设计    "@codebase 如何给这个项目添加缓存层?"    │  │
│  │  [4] 学习提问    "这里用到了什么设计模式? 为什么?"        │  │
│  │  [5] 代码审查    "审查这个PR的代码质量和安全性"           │  │
│  │  [6] 性能分析    "@file:api.ts 这个文件有什么性能瓶颈?"  │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │                  Apply 按钮                               │  │
│  │                                                          │  │
│  │  Chat 回复中的代码块旁边有 "Apply" 按钮                  │  │
│  │  点击后自动将代码应用到对应文件,显示 diff 预览            │  │
│  │  流程: Chat建议 -> Apply -> diff预览 -> Accept/Reject    │  │
│  └──────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────┘

Chat 对话示例

python
# ============================================================
# 场景: 在 Chat 中输入以下内容进行项目分析
# ============================================================

# 用户输入: "@codebase 帮我分析这个项目的数据库访问模式,
#           是否存在 N+1 查询问题?"

# Cursor Chat 会:
# 1. 扫描整个代码库的数据库相关代码
# 2. 识别 ORM 查询模式
# 3. 指出潜在的 N+1 问题
# 4. 给出修复建议

# 示例: Chat 发现的 N+1 问题
# ---- 有问题的代码 ----
class OrderService:
    def get_orders_with_items(self, user_id: int):
        """获取用户的所有订单及商品 - 存在 N+1 问题"""
        orders = Order.query.filter_by(user_id=user_id).all()  # 1次查询

        result = []
        for order in orders:
            items = OrderItem.query.filter_by(order_id=order.id).all()  # N次查询!
            result.append({
                "order": order,
                "items": items
            })
        return result  # 总共 N+1 次数据库查询


# ---- Chat 建议的修复 ----
class OrderServiceOptimized:
    def get_orders_with_items(self, user_id: int):
        """获取用户的所有订单及商品 - 使用 eager loading 优化"""
        # 使用 joinedload 一次性加载关联数据, 只需1次查询
        orders = (
            Order.query
            .options(joinedload(Order.items))
            .filter_by(user_id=user_id)
            .all()
        )

        return [
            {"order": order, "items": order.items}
            for order in orders
        ]  # 总共只需 1 次数据库查询

@doc 引用外部文档

typescript
// ============================================================
// 场景: 引用第三方库文档来生成代码
// Chat 输入: "@doc https://docs.stripe.com/api/charges
//            帮我用 Node.js 实现 Stripe 支付流程"
// ============================================================

// Cursor 会阅读 Stripe 文档并生成符合最新 API 的代码:

import Stripe from 'stripe';

const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
    apiVersion: '2023-10-16'
});

interface PaymentParams {
    amount: number;       // 金额(分)
    currency: string;     // 货币类型
    customerId: string;   // 客户ID
    description?: string; // 描述
}

// 创建支付意图 (Payment Intent)
async function createPayment(params: PaymentParams) {
    try {
        const paymentIntent = await stripe.paymentIntents.create({
            amount: params.amount,
            currency: params.currency,
            customer: params.customerId,
            description: params.description,
            automatic_payment_methods: {
                enabled: true,  // 自动启用可用的支付方式
            },
        });

        return {
            success: true,
            clientSecret: paymentIntent.client_secret,
            paymentIntentId: paymentIntent.id,
            status: paymentIntent.status
        };
    } catch (error) {
        if (error instanceof Stripe.errors.StripeCardError) {
            return { success: false, error: '卡片被拒绝', code: error.code };
        }
        throw error;
    }
}

// 确认支付
async function confirmPayment(paymentIntentId: string) {
    const paymentIntent = await stripe.paymentIntents.retrieve(paymentIntentId);

    if (paymentIntent.status === 'succeeded') {
        return { success: true, message: '支付成功' };
    } else if (paymentIntent.status === 'requires_action') {
        return { success: false, message: '需要额外验证', requiresAction: true };
    } else {
        return { success: false, message: `支付状态: ${paymentIntent.status}` };
    }
}

// Webhook 处理支付事件
async function handleWebhook(payload: string, signature: string) {
    const event = stripe.webhooks.constructEvent(
        payload,
        signature,
        process.env.STRIPE_WEBHOOK_SECRET!
    );

    switch (event.type) {
        case 'payment_intent.succeeded':
            console.log('支付成功:', event.data.object);
            break;
        case 'payment_intent.payment_failed':
            console.log('支付失败:', event.data.object);
            break;
        default:
            console.log('未处理的事件类型:', event.type);
    }
}

Composer 多文件编辑

Composer 工作原理

┌────────────────────────────────────────────────────────────────┐
│                Composer 多文件编辑流程                          │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Step 1: 打开 Composer (Ctrl+Shift+I)                   │  │
│  │  ┌──────────────────────────────────────────────┐       │  │
│  │  │  描述你的需求:                                │       │  │
│  │  │  "给这个Express项目添加JWT认证中间件,          │       │  │
│  │  │   需要修改路由文件、创建中间件文件、             │       │  │
│  │  │   更新配置文件和添加相关测试"                   │       │  │
│  │  └──────────────────────────────────────────────┘       │  │
│  └──────────────────────────────────────────────────────────┘  │
│                          │                                     │
│                          v                                     │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Step 2: Composer 分析项目结构                           │  │
│  │  ┌────────────────┐  ┌────────────────┐                 │  │
│  │  │ 扫描文件结构    │  │ 理解依赖关系    │                 │  │
│  │  │ src/            │  │ routes -> auth  │                 │  │
│  │  │ ├── routes/     │  │ auth -> config  │                 │  │
│  │  │ ├── middleware/ │  │ test -> all     │                 │  │
│  │  │ ├── config/     │  │                 │                 │  │
│  │  │ └── tests/      │  │                 │                 │  │
│  │  └────────────────┘  └────────────────┘                 │  │
│  └──────────────────────────────────────────────────────────┘  │
│                          │                                     │
│                          v                                     │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Step 3: 生成多文件变更计划                              │  │
│  │                                                          │  │
│  │  [新建] src/middleware/auth.js      认证中间件            │  │
│  │  [修改] src/routes/api.js           添加认证保护          │  │
│  │  [修改] src/config/index.js         添加JWT配置           │  │
│  │  [修改] package.json                添加jsonwebtoken依赖  │  │
│  │  [新建] src/tests/auth.test.js      认证测试              │  │
│  └──────────────────────────────────────────────────────────┘  │
│                          │                                     │
│                          v                                     │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  Step 4: 逐文件预览和确认                                │  │
│  │                                                          │  │
│  │  每个文件显示 diff 对比:                                  │  │
│  │  ┌────────────────────────────────────────────┐          │  │
│  │  │  - const express = require('express');      │          │  │
│  │  │  + const express = require('express');      │          │  │
│  │  │  + const { authenticate } = require(        │          │  │
│  │  │  +     '../middleware/auth'                  │          │  │
│  │  │  + );                                       │          │  │
│  │  └────────────────────────────────────────────┘          │  │
│  │                                                          │  │
│  │  [Accept All] [Accept File] [Reject] [Edit]              │  │
│  └──────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────┘

Composer 实战: 添加认证系统

javascript
// ============================================================
// Composer 生成的文件1: src/middleware/auth.js
// ============================================================

const jwt = require('jsonwebtoken');
const { JWT_SECRET, JWT_EXPIRES_IN } = require('../config');

/**
 * JWT 认证中间件
 * 验证请求头中的 Bearer Token
 */
function authenticate(req, res, next) {
    // 从 Authorization 头获取 token
    const authHeader = req.headers.authorization;
    if (!authHeader || !authHeader.startsWith('Bearer ')) {
        return res.status(401).json({
            error: '未提供认证令牌',
            code: 'AUTH_TOKEN_MISSING'
        });
    }

    const token = authHeader.split(' ')[1];

    try {
        // 验证 token
        const decoded = jwt.verify(token, JWT_SECRET);
        req.user = decoded;  // 将用户信息附加到请求对象
        next();
    } catch (error) {
        if (error.name === 'TokenExpiredError') {
            return res.status(401).json({
                error: '令牌已过期',
                code: 'AUTH_TOKEN_EXPIRED'
            });
        }
        return res.status(403).json({
            error: '无效的认证令牌',
            code: 'AUTH_TOKEN_INVALID'
        });
    }
}

/**
 * 角色授权中间件
 * 检查用户是否拥有指定角色
 */
function authorize(...roles) {
    return (req, res, next) => {
        if (!req.user) {
            return res.status(401).json({ error: '未认证' });
        }
        if (!roles.includes(req.user.role)) {
            return res.status(403).json({
                error: '权限不足',
                required: roles,
                current: req.user.role
            });
        }
        next();
    };
}

/**
 * 生成 JWT 令牌
 */
function generateToken(payload) {
    return jwt.sign(payload, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN });
}

module.exports = { authenticate, authorize, generateToken };
javascript
// ============================================================
// Composer 生成的文件2: src/routes/auth.js
// ============================================================

const express = require('express');
const bcrypt = require('bcryptjs');
const { generateToken, authenticate } = require('../middleware/auth');
const router = express.Router();

// 模拟用户数据库
const users = new Map();

// POST /auth/register - 用户注册
router.post('/register', async (req, res) => {
    try {
        const { username, email, password } = req.body;

        // 参数验证
        if (!username || !email || !password) {
            return res.status(400).json({ error: '缺少必填字段' });
        }

        // 检查用户是否已存在
        if (users.has(email)) {
            return res.status(409).json({ error: '邮箱已注册' });
        }

        // 加密密码
        const salt = await bcrypt.genSalt(12);
        const hashedPassword = await bcrypt.hash(password, salt);

        // 存储用户
        const user = {
            id: users.size + 1,
            username,
            email,
            password: hashedPassword,
            role: 'user',
            createdAt: new Date()
        };
        users.set(email, user);

        // 生成令牌
        const token = generateToken({
            userId: user.id,
            email: user.email,
            role: user.role
        });

        res.status(201).json({
            message: '注册成功',
            token,
            user: { id: user.id, username, email, role: user.role }
        });
    } catch (error) {
        res.status(500).json({ error: '服务器内部错误' });
    }
});

// POST /auth/login - 用户登录
router.post('/login', async (req, res) => {
    try {
        const { email, password } = req.body;

        const user = users.get(email);
        if (!user) {
            return res.status(401).json({ error: '邮箱或密码错误' });
        }

        const isMatch = await bcrypt.compare(password, user.password);
        if (!isMatch) {
            return res.status(401).json({ error: '邮箱或密码错误' });
        }

        const token = generateToken({
            userId: user.id,
            email: user.email,
            role: user.role
        });

        res.json({
            message: '登录成功',
            token,
            user: { id: user.id, username: user.username, email, role: user.role }
        });
    } catch (error) {
        res.status(500).json({ error: '服务器内部错误' });
    }
});

// GET /auth/me - 获取当前用户信息(需要认证)
router.get('/me', authenticate, (req, res) => {
    const user = users.get(req.user.email);
    if (!user) {
        return res.status(404).json({ error: '用户不存在' });
    }
    res.json({
        id: user.id,
        username: user.username,
        email: user.email,
        role: user.role
    });
});

module.exports = router;

与GitHub Copilot对比

功能对比矩阵

┌────────────────────────────────────────────────────────────────────┐
│              Cursor vs GitHub Copilot 深度对比                      │
├────────────────┬────────────────────┬──────────────────────────────┤
│  对比维度       │  Cursor             │  GitHub Copilot              │
├────────────────┼────────────────────┼──────────────────────────────┤
│  产品形态       │  独立编辑器(VS Code  │  IDE 插件                    │
│                │  分叉)              │                              │
│  AI 模型       │  GPT-4o / Claude /  │  OpenAI Codex (专用)         │
│                │  可选模型           │                              │
│  代码补全       │  Tab 补全           │  Tab 补全 (更成熟)           │
│  内联编辑       │  Cmd+K (核心优势)   │  无                          │
│  Chat 功能     │  Ctrl+L (强)        │  Copilot Chat (强)           │
│  多文件编辑     │  Composer (核心优势)│  无                          │
│  代码库理解     │  @codebase 索引     │  @workspace (较弱)           │
│  外部文档       │  @doc URL引用       │  无                          │
│  联网搜索       │  @web 支持          │  无                          │
│  终端集成       │  Ctrl+K in Terminal │  @terminal                   │
│  隐私模式       │  支持               │  企业版支持                   │
│  价格           │  $20/月 (Pro)       │  $10/月 (Individual)         │
│  学习曲线       │  需要适应新编辑器    │  在现有IDE中使用             │
├────────────────┴────────────────────┴──────────────────────────────┤
│                                                                    │
│  选择建议:                                                         │
│  ┌──────────────────────────────────────────────────────────────┐  │
│  │  选 Cursor 如果:                                             │  │
│  │  - 需要频繁的代码重构和多文件修改                              │  │
│  │  - 想要更强的代码库级别理解                                    │  │
│  │  - 愿意尝试 AI 原生的编辑器体验                               │  │
│  │  - 需要引用外部文档生成代码                                    │  │
│  │                                                              │  │
│  │  选 Copilot 如果:                                            │  │
│  │  - 不想离开熟悉的 IDE (特别是JetBrains用户)                   │  │
│  │  - 主要需求是代码补全                                         │  │
│  │  - 已有 GitHub 企业版订阅                                     │  │
│  │  - 团队统一使用 Copilot 且有组织策略管控需求                   │  │
│  └──────────────────────────────────────────────────────────────┘  │
└────────────────────────────────────────────────────────────────────┘

高级技巧与工作流

.cursorrules 项目规则

┌────────────────────────────────────────────────────────────────┐
│             .cursorrules 项目级AI规则配置                       │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  在项目根目录创建 .cursorrules 文件                             │
│  Cursor 会在每次 AI 请求时自动注入这些规则                      │
│  相当于给 AI 一份"项目编码规范手册"                             │
│                                                                │
│  作用:                                                         │
│  - 统一团队的AI输出风格                                        │
│  - 减少重复的Prompt说明                                        │
│  - 确保生成代码符合项目架构                                    │
│  - 强制安全和最佳实践                                          │
└────────────────────────────────────────────────────────────────┘
markdown
<!-- 示例 .cursorrules 文件内容 -->

# 项目规范

## 技术栈
- 后端: Python 3.11 + FastAPI + SQLAlchemy 2.0
- 前端: React 18 + TypeScript + TailwindCSS
- 数据库: PostgreSQL 15
- 缓存: Redis

## 编码规范
- Python 使用 Google 风格的 docstring
- 所有函数必须有类型提示
- 使用 async/await 而非同步代码
- 错误处理使用自定义异常类, 不要用通用 Exception
- 变量命名使用 snake_case, 类名使用 PascalCase

## 项目结构
- API 路由放在 src/routes/ 目录
- 业务逻辑放在 src/services/ 目录
- 数据模型放在 src/models/ 目录
- 工具函数放在 src/utils/ 目录

## 安全要求
- 所有用户输入必须验证和清洗
- 数据库查询必须使用参数化查询
- 敏感配置必须从环境变量读取
- API 响应不得泄露内部实现细节

## 测试要求
- 每个 Service 函数都要有对应的单元测试
- 测试文件命名: test_[模块名].py
- 使用 pytest + pytest-asyncio

高效工作流模式

┌────────────────────────────────────────────────────────────────┐
│            Cursor 日常开发工作流                                 │
├────────────────────────────────────────────────────────────────┤
│                                                                │
│  阶段1: 需求理解 (Chat)                                        │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  "@codebase 当前项目的架构是什么?                         │  │
│  │   我需要添加一个通知系统, 应该如何设计?"                   │  │
│  └──────────────────────────────────────────────────────────┘  │
│                          |                                     │
│                          v                                     │
│  阶段2: 代码生成 (Composer)                                    │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  "根据刚才的设计方案, 创建通知服务相关的所有文件:           │  │
│  │   模型、服务层、路由、测试"                                │  │
│  └──────────────────────────────────────────────────────────┘  │
│                          |                                     │
│                          v                                     │
│  阶段3: 细节调整 (Cmd+K)                                      │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  选中生成的代码, Cmd+K:                                   │  │
│  │  "添加邮件和短信两种通知渠道"                              │  │
│  │  "给这个函数添加限流逻辑, 每用户每分钟最多10条"            │  │
│  └──────────────────────────────────────────────────────────┘  │
│                          |                                     │
│                          v                                     │
│  阶段4: 审查优化 (Chat)                                       │
│  ┌──────────────────────────────────────────────────────────┐  │
│  │  选中所有新增代码, Ctrl+L:                                │  │
│  │  "审查这段代码的安全性、性能和可维护性"                    │  │
│  └──────────────────────────────────────────────────────────┘  │
│                                                                │
└────────────────────────────────────────────────────────────────┘

实战项目案例

用 Composer 搭建 REST API 脚手架

python
# ============================================================
# Composer 指令:
# "创建一个完整的 FastAPI 项目结构, 包含:
#  1. 用户认证 (JWT)
#  2. 数据库模型 (SQLAlchemy)
#  3. CRUD 路由
#  4. 请求验证 (Pydantic)
#  5. 错误处理中间件
#  6. 日志配置"
#
# Composer 会一次性生成以下所有文件:
# ============================================================

# --- 文件: src/models/user.py ---
from sqlalchemy import Column, Integer, String, Boolean, DateTime
from sqlalchemy.sql import func
from src.database import Base

class User(Base):
    __tablename__ = "users"

    id = Column(Integer, primary_key=True, index=True)
    username = Column(String(50), unique=True, nullable=False, index=True)
    email = Column(String(100), unique=True, nullable=False, index=True)
    hashed_password = Column(String(255), nullable=False)
    full_name = Column(String(100))
    is_active = Column(Boolean, default=True)
    is_admin = Column(Boolean, default=False)
    created_at = Column(DateTime(timezone=True), server_default=func.now())
    updated_at = Column(DateTime(timezone=True), onupdate=func.now())


# --- 文件: src/schemas/user.py ---
from pydantic import BaseModel, EmailStr
from typing import Optional
from datetime import datetime

class UserBase(BaseModel):
    username: str
    email: EmailStr
    full_name: Optional[str] = None

class UserCreate(UserBase):
    password: str

class UserUpdate(BaseModel):
    email: Optional[EmailStr] = None
    full_name: Optional[str] = None
    is_active: Optional[bool] = None

class UserResponse(UserBase):
    id: int
    is_active: bool
    created_at: datetime

    class Config:
        from_attributes = True


# --- 文件: src/middleware/error_handler.py ---
from fastapi import Request
from fastapi.responses import JSONResponse
import logging

logger = logging.getLogger(__name__)

class AppException(Exception):
    """自定义应用异常基类"""
    def __init__(self, status_code: int, detail: str, error_code: str = None):
        self.status_code = status_code
        self.detail = detail
        self.error_code = error_code

class NotFoundError(AppException):
    def __init__(self, resource: str):
        super().__init__(404, f"{resource}不存在", "NOT_FOUND")

class ConflictError(AppException):
    def __init__(self, message: str):
        super().__init__(409, message, "CONFLICT")

class UnauthorizedError(AppException):
    def __init__(self, message: str = "未授权"):
        super().__init__(401, message, "UNAUTHORIZED")

async def app_exception_handler(request: Request, exc: AppException):
    logger.warning(f"AppException: {exc.detail} | Path: {request.url.path}")
    return JSONResponse(
        status_code=exc.status_code,
        content={
            "error": exc.detail,
            "code": exc.error_code,
            "path": str(request.url.path)
        }
    )

总结

本教程涵盖了 Cursor 编辑器的核心内容:

  1. 核心优势: AI 原生编辑器,三大核心功能(Cmd+K / Chat / Composer)深度融合
  2. 安装配置: 从 VS Code 无缝迁移,模型选择和隐私设置
  3. Cmd+K: 最高频功能,无选中生成代码/选中修改代码/终端命令生成
  4. Chat: @上下文引用系统(@codebase/@file/@doc/@web),Apply一键应用
  5. Composer: 多文件编辑的核心武器,适合大规模代码变更和项目脚手架搭建
  6. 与Copilot对比: Cursor 在多文件编辑和代码库理解方面优势明显
  7. 高级技巧: .cursorrules 项目规则、四阶段工作流、上下文管理

参考资源


创建时间: 2024-01-15 最后更新: 2024-01-15

💬 讨论

使用 GitHub 账号登录后即可参与讨论

基于 MIT 许可发布