> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Fetch Metadata

> 使用 Sec-Fetch-* header 的安全中间件，帮助你的 Laravel 应用抵御 CSRF 攻击和跨站请求。

## 概览

[revolution/laravel-fetch-metadata](https://github.com/invokable/laravel-fetch-metadata) 是一个用于校验浏览器发送的 `Sec-Fetch-*` HTTP header 的安全中间件包。你可以根据请求的发起来源、模式、目标以及是否由用户操作触发，来控制允许通过的请求。

借助浏览器内建的安全能力，可以在不影响正常用户体验的前提下，阻止来自恶意来源的非法请求。

<Info>
  在 Laravel 13 中，CSRF 保护的 Origin 校验开始使用 `Sec-Fetch-Site` header。详情请参考 [CSRF 保护](/zh/csrf)。
</Info>

关于 Fetch Metadata 的详细规范，请参考 [MDN 文档](https://developer.mozilla.org/ja/docs/Glossary/Fetch_metadata_request_header)。

## 安装

```bash theme={null}
composer require revolution/laravel-fetch-metadata
```

### 注册中间件别名

在 `bootstrap/app.php` 中注册中间件别名。

```php theme={null}
use Illuminate\Foundation\Configuration\Middleware;
use Revolution\FetchMetadata\Middleware\SecFetchSite;
use Revolution\FetchMetadata\Middleware\SecFetchMode;
use Revolution\FetchMetadata\Middleware\SecFetchDest;
use Revolution\FetchMetadata\Middleware\SecFetchUser;

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'sec-fetch-site' => SecFetchSite::class,
        'sec-fetch-mode' => SecFetchMode::class,
        'sec-fetch-dest' => SecFetchDest::class,
        'sec-fetch-user' => SecFetchUser::class,
    ]);
})
```

你也可以只使用其中的一部分中间件。别名可以任意修改。

## 中间件说明

### SecFetchSite

`Sec-Fetch-Site` header 表示请求的发起来源与目标 origin 之间的关系。默认只允许 `same-origin` 与 `none`（直接访问）。

| 值             | 说明                   |
| ------------- | -------------------- |
| `same-origin` | 来自同一 origin 的请求      |
| `same-site`   | 来自同一 site（如子域名）的请求   |
| `cross-site`  | 来自不同 site 的请求        |
| `none`        | 用户直接输入 URL 等由导航发起的请求 |

详情请参考 [MDN 文档](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Sec-Fetch-Site)。

### SecFetchMode

`Sec-Fetch-Mode` header 表示请求的模式。默认允许 `navigate` 与 `cors`。

| 值             | 说明                 |
| ------------- | ------------------ |
| `navigate`    | 由链接点击、表单提交等发起的导航请求 |
| `cors`        | CORS 请求            |
| `no-cors`     | no-cors 请求         |
| `same-origin` | 同 origin 请求        |
| `websocket`   | WebSocket 连接请求     |

详情请参考 [MDN 文档](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Sec-Fetch-Mode)。

### SecFetchDest

`Sec-Fetch-Dest` header 表示请求目标资源的类型。

详情请参考 [MDN 文档](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Sec-Fetch-Dest)。

### SecFetchUser

`Sec-Fetch-User` header 表示请求是否由用户操作触发。值只有 `?1`（有用户操作）。

<Warning>
  使用 `SecFetchUser` 中间件会同时拦截搜索引擎爬虫和 AI agent。请不要用在需要被索引的公开页面上。
</Warning>

## 在路由中的使用示例

### 基本用法

```php theme={null}
use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;

Route::post('user/update-password', function (Request $request) {
    //
})->middleware('sec-fetch-site');
```

### 通过参数指定允许值

```php theme={null}
Route::post('user/update-password', function (Request $request) {
    //
})->middleware('sec-fetch-site:cross-site');
```

### 指定多个参数

```php theme={null}
Route::post('user/update-password', function (Request $request) {
    //
})->middleware('sec-fetch-site:same-origin,cross-site');
```

### 不使用别名的情况

```php theme={null}
use Revolution\FetchMetadata\Middleware\SecFetchSite;

Route::post('user/update-password', function (Request $request) {
    //
})->middleware(SecFetchSite::class.':same-origin,cross-site');
```

### 组合多个中间件

```php theme={null}
Route::post('user/update-profile', function (Request $request) {
    //
})->middleware(['sec-fetch-site:same-origin', 'sec-fetch-mode:navigate']);
```

## 错误处理

当 `Sec-Fetch-*` header 的值不合法时，会抛出 `Symfony\Component\HttpKernel\Exception\BadRequestHttpException`。

可以在 `bootstrap/app.php` 中自定义响应。

```php theme={null}
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (BadRequestHttpException $e, Request $request) {
        if ($request->expectsJson()) {
            return response()->json([
                'message' => $e->getMessage(),
            ], 400);
        }
    });
})
```

## 与 CSRF 保护的关系

在 Laravel 13 中，`PreventRequestForgery` 中间件作为 CSRF 保护的第一步，会通过 `Sec-Fetch-Site` header 进行 Origin 校验。本包在更细粒度上进一步利用 Fetch Metadata header，可以进一步增强应用的安全性。

详情请参考 [CSRF 保护](/zh/csrf)。

<Info>
  最新信息请参考 [GitHub 仓库](https://github.com/invokable/laravel-fetch-metadata)。
</Info>


## Related topics

- [Laravel 12 升级到 13 指南](/zh/blog/upgrade-12-to-13.md)
- [Socialite - Laravel Bluesky](/zh/packages/laravel-bluesky/socialite.md)
- [会话上下文与过滤](/zh/packages/laravel-copilot-sdk/session-context.md)
- [Laravel MCP](/zh/mcp.md)
- [会话恢复](/zh/packages/laravel-copilot-sdk/resume.md)
