Skip to content

第 2.5 章:API 路由

学习时间: 45 分钟


1. 什么是路由?通俗易懂的解释

想象一下,您的控制器 (PlanetController) 是一个大型办公中心,它的每个方法 (index, store, show) 都是一个执行自身工作的部门。

路由 (Route) 是建筑物入口处的地址牌。它指明:

  • “如果有人使用 GET 方法访问 /planets 地址——将其发送到 index 部门(显示所有)。”
  • “如果有人使用 POST 方法访问 /planets 地址并携带数据——将其发送到 store 部门(创建新记录)。”

没有路由,外部世界的任何请求都无法在您的代码中找到它所需的部门。API 中此类“地址牌”的主要文件是 routes/api.php

在 Laravel 11+ 中,默认没有“API 地址簿”。我们通过执行 php artisan install:api 命令自行创建了它。现在我们有了 routes/api.php 文件——它是我们 API 所有路由的主要管理中心。

api.phpweb.php 的主要区别:

  • /api 前缀:Laravel 会自动为此文件中的所有 URL 地址添加 /api 前缀。/planets 路由会变为 /api/planets
  • “无状态” (Stateless):这里没有像普通 Web 应用那样的会话和 Cookie 文件。每个请求都是独立的,并且必须包含所有身份验证信息(通常是请求头中的 API 令牌)。

2. 新手之路:手动创建路由

让我们手动创建一个路由,以便理解其原理。我们的目标是让 URL /api/planets 显示所有行星的列表。

打开 routes/api.php 并写入:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PlanetController; // 指明控制器位置

//                    (1)           (2)                     (3)
Route::get(      '/planets',    [PlanetController::class, 'index']     );
//   ^               ^                       ^
// (HTTP 方法)   (URL 地址)          (要调用哪个控制器和方法)

逐行分析这段代码:

  1. Route::get(...) — 我们说:“这个路由仅适用于 GET 请求。”
  2. '/planets' — 这是 Laravel 将监听的 URL。考虑到 /api 前缀,完整地址将是 http://space-api.test/api/planets
  3. [PlanetController::class, 'index'] — 这是“目的地”。我们说:“当请求到来时,找到 PlanetController 类并调用其中的 index() 方法。”

现在一切都关联起来了! 请求 -> 路由 -> 控制器 -> 方法。

那么,如果我们需要通过行星 ID 获取一个行星呢?例如,/api/planets/5

// 获取特定行星的路由
Route::get('/planets/{planet}', [PlanetController::class, 'show']);

这里 {planet} 是一个“模板”或变量。Laravel 明白这个位置可以是任何内容(ID、slug)。然后它将此值传递给 show(Planet $planet) 方法。Laravel 自动通过 ID 查找行星的这种“魔力”称为 路由模型绑定 (Route Model Binding)


3. 大师之路:apiResource —— 一行代码统治一切

手动为每个路由(index, show, store, update, destroy)创建很繁琐。Laravel 开发者明白这一点,因此创建了一个强大的助手——apiResource

删除我们所写的所有内容,并用一行代码替换:

<?php

use Illuminate\Support\Facades\Route;
use App\Http\Controllers\PlanetController;

Route::apiResource('planets', PlanetController::class);

这一行代码在底层做了什么? 它会自动为我们在控制器中已经实现的标准 CRUD 操作创建一整套路由。

方法 URL 映射到方法 用途
GET /api/planets index() 获取所有行星列表
POST /api/planets store() 创建一个新行星
GET /api/planets/{planet} show() 显示一个特定的行星
PUT/PATCH /api/planets/{planet} update() 更新现有行星
DELETE /api/planets/{planet} destroy() 删除行星

您可以亲自验证。在终端中执行命令:

php artisan route:list --path=api

您将看到一个包含所有已创建路由的表格。apiResource 是您在创建标准 API 时节省时间的最佳伙伴。


4. 特殊任务和路由顺序

如果我们需要一个 apiResource 中没有的非标准路由怎么办?例如,通过地址 /api/planets/random 获取一个随机行星。

让我们添加它。但这里有一个致命陷阱,十有八九的新手都会掉进去。

错误的顺序 (不工作!):

Route::apiResource('planets', PlanetController::class);
Route::get('/planets/random', [PlanetController::class, 'random']); // <-- 不工作
为什么? Laravel 从上到下读取路由。它会看到 Route::apiResource,它创建了 GET /planets/{planet} 路由。当您请求 /planets/random 时,Laravel 会认为 "random" 是行星的 ID,并尝试在数据库中查找 ID 为 "random" 的行星,您将收到错误。

正确的顺序 (工作!):

<?php
use App\Http\Controllers\PlanetController;
use Illuminate\Support\Facades\Route;

// 1. 首先声明具体路由
Route::get('/planets/random', [PlanetController::class, 'random']);

// 2. 然后才声明带变量的通用路由
Route::apiResource('planets', PlanetController::class);

⚠️ 重要提示!

为了测试 api/planets/random 路由,需要在 PlanetController 中添加一个新的处理程序:

<?php
public function random(Request $request)
{
   $planet = Planet::inRandomOrder()->first();
   return response()->json($planet);
}

规则: 始终在更通用和模板化的路由(例如 /{planet}之前声明更具体的路由(例如 /random)。


5. 路由分组:整理顺序

当路由数量增多时,可以并且应该对它们进行分组。

A. API 版本控制 为了将来不破坏使用您的 API 的旧应用程序,通常会在 URL 中添加版本,例如 /api/v1/...

<?php
Route::prefix('v1')->group(function () {
    // 此组内的所有路由都将获得 /v1 前缀
    // 最终 URL: /api/v1/planets
    Route::get('/planets/random', [PlanetController::class, 'random']);
    Route::apiResource('planets', PlanetController::class);
});

B. 路由保护 (中间件) 假设所有人都可以查看行星,但只有授权用户才能创建、更新和删除行星。

<?php
// 对所有人公开的路由
Route::get('/planets', [PlanetController::class, 'index']);
Route::get('/planets/{planet}', [PlanetController::class, 'show']);

// 需要“通行证”(身份验证)的路由组
Route::middleware('auth:sanctum')->group(function () {
    Route::post('/planets', [PlanetController::class, 'store']);
    Route::put('/planets/{planet}', [PlanetController::class, 'update']);
    Route::delete('/planets/{planet}', [PlanetController::class, 'destroy']);
});

这里 middleware('auth:sanctum') 就像一个保安,检查每个试图访问组内路由的人的“通行证”。


6. 通过 Postman 进行测试

现在所有路由都已设置好,是时候进行测试了。

  1. 如果您使用 Herd: 您的网站已在 http://space-api.test 之类的地址上运行。
  2. 如果没有: 通过命令 php artisan serve 启动本地服务器。地址将是 http://localhost:8000

打开 Postman 并发送请求:

  • GET http://space-api.test/api/planets
  • GET http://space-api.test/api/planets/random
  • POST http://space-api.test/api/planets (不要忘记在 Body -> raw -> JSON 选项卡中添加 JSON 请求体)。

POST 请求示例:

{
    "name": "Kepler-186f",
    "description": "宜居带中第一个地球大小的行星",
    "size_km": 15000,
    "solar_system": "Kepler-186",
    "is_habitable": true
}


8. 常见的路由错误

  1. 404 Not Found
    • URL 不正确 (/api/planet 而不是 /api/planets)
    • 忘记运行 php artisan serve
  2. 405 Method Not Allowed
    • HTTP 方法不正确(例如,GET 而不是 POST)
  3. Missing Controller
    • 控制器名称拼写错误 (PlanetControler)
  4. Route Name Collision
    • 路由名称冲突

巩固知识的小测验

1. Laravel 中用于 API 路由的文件是:

2. API 路由的自动前缀是:

3. 用于创建 5 个 CRUD 路由的方法是:

4. Route::prefix('v1') 用于:

5. 查看所有路由的命令是:


🚀 本章总结:

您已经为宇宙 API 构建了“超空间路由”!现在:

  • 🗺️ 所有端点均可通过 /api/... 访问
  • 🔗 资源路由已连接到控制器
  • 🛡️ 已添加自定义路由以进行特殊操作
  • ✅ 路由已通过 Postman 测试

宇宙已开放请求! 接下来,我们将添加针对“太空垃圾”的防护 — 数据验证。

📌 检查:

  1. 执行 php artisan route:list
  2. 确认您能看到 5+ 个 planets 路由
  3. 在浏览器/Postman 中测试 GET /api/planets 的工作情况

⚠️ 如果出现 404 错误:

  • 检查 routes/api.php 中是否存在 Route::apiResource
  • 确保服务器已启动 (php artisan serve)
  • 对于 Windows:在防火墙中允许端口 8000