hyperf/docs/zh-tw/request.md

302 lines
9.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 請求物件
`請求物件(Request)` 是完全基於 [PSR-7](https://www.php-fig.org/psr/psr-7/) 標準實現的,由 [hyperf/http-message](https://github.com/hyperf/http-message) 元件提供實現支援。
> 注意 [PSR-7](https://www.php-fig.org/psr/psr-7/) 標準為 `請求(Request)` 進行了 `immutable 機制` 的設計,所有以 `with` 開頭的方法的返回值都是一個新物件,不會修改原物件的值
## 安裝
該元件完全獨立,適用於任何一個框架專案。
```bash
composer require hyperf/http-message
```
> 如用於其它框架專案則僅支援 PSR-7 提供的 API具體可直接查閱 PSR-7 的相關規範,該文件所描述的使用方式僅限於使用 Hyperf 時的用法。
## 獲得請求物件
可以通過容器注入 `Hyperf\HttpServer\Contract\RequestInterface` 獲得 對應的 `Hyperf\HttpServer\Request`,實際注入的物件為一個代理物件,代理的物件為每個請求的 `PSR-7 請求物件(Request)`,也就意味著僅可在 `onRequest` 生命週期內可獲得此物件,下面是一個獲取示例:
```php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\AutoController;
/**
* @AutoController()
*/
class IndexController
{
public function info(RequestInterface $request)
{
// ...
}
}
```
### 依賴注入與引數
如果希望通過控制器方法引數獲取路由引數,可以在依賴項之後列出對應的引數,框架會自動將對應的引數注入到方法引數內,比如您的路由是這樣定義的:
```php
// 註解方式
/**
* @GetMapping(path="/user/{id:\d+}")
*/
// 配置方式
use Hyperf\HttpServer\Router\Router;
Router::addRoute(['GET', 'HEAD'], '/user/{id:\d+}', [\App\Controller\IndexController::class, 'user']);
```
則可以通過在方法引數上宣告 `$id` 引數獲得 `Query` 引數 `id`,如下所示:
```php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\AutoController;
/**
* @AutoController()
*/
class IndexController
{
public function info(RequestInterface $request, int $id)
{
// ...
}
}
```
除了可以通過依賴注入獲取路由引數,還可以通過 `route` 方法獲取,如下所示:
```php
declare(strict_types=1);
namespace App\Controller;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\HttpServer\Annotation\AutoController;
/**
* @AutoController()
*/
class IndexController
{
public function info(RequestInterface $request)
{
// 存在則返回,不存在則返回預設值 null
$id = $request->route('id');
// 存在則返回,不存在則返回預設值 0
$id = $request->route('id', 0);
// ...
}
}
```
### 請求路徑 & 方法
`Hyperf\HttpServer\Contract\RequestInterface` 除了使用 [PSR-7](https://www.php-fig.org/psr/psr-7/) 標準定義的 `APIs` 之外,還提供了多種方法來檢查請求,下面我們提供一些方法的示例:
#### 獲取請求路徑
`path()` 方法返回請求的路徑資訊。也就是說,如果傳入的請求的目標地址是 `http://domain.com/foo/bar?baz=1`,那麼 `path()` 將會返回 `foo/bar`
```php
$uri = $request->path();
```
`is(...$patterns)` 方法可以驗證傳入的請求路徑和指定規則是否匹配。使用這個方法的時,你也可以傳遞一個 `*` 字元作為萬用字元:
```php
if ($request->is('user/*')) {
// ...
}
```
#### 獲取請求的 URL
你可以使用 `url()``fullUrl()` 方法去獲取傳入請求的完整 `URL`。`url()` 方法返回不帶有 `Query 引數``URL`,而 `fullUrl()` 方法的返回值包含 `Query 引數`
```php
// 沒有查詢引數
$url = $request->url();
// 帶上查詢引數
$url = $request->fullUrl();
```
#### 獲取請求方法
`getMethod()` 方法將返回 `HTTP` 的請求方法。你也可以使用 `isMethod(string $method)` 方法去驗證 `HTTP` 的請求方法與指定規則是否匹配:
```php
$method = $request->getMethod();
if ($request->isMethod('post')) {
// ...
}
```
### PSR-7 請求及方法
[hyperf/http-message](https://github.com/hyperf/http-message) 元件本身是一個實現了 [PSR-7](https://www.php-fig.org/psr/psr-7/) 標準的元件,相關方法都可以通過注入的 `請求物件(Request)` 來呼叫。
如果注入時宣告為 [PSR-7](https://www.php-fig.org/psr/psr-7/) 標準的 `Psr\Http\Message\ServerRequestInterface` 介面,則框架會自動轉換為等同於 `Hyperf\HttpServer\Contract\RequestInterface``Hyperf\HttpServer\Request` 物件。
> 建議使用 `Hyperf\HttpServer\Contract\RequestInterface` 來注入,這樣可獲得 IDE 對專屬方法的自動完成提醒支援。
## 輸入預處理 & 規範化
## 獲取輸入
### 獲取所有輸入
您可以使用 `all()` 方法以 `陣列` 形式獲取到所有輸入資料:
```php
$all = $request->all();
```
### 獲取指定輸入值
通過 `input(string $key, $default = null)``inputs(array $keys, $default = null): array` 獲取 `一個``多個` 任意形式的輸入值:
```php
// 存在則返回,不存在則返回 null
$name = $request->input('name');
// 存在則返回,不存在則返回預設值 Hyperf
$name = $request->input('name', 'Hyperf');
```
如果傳輸表單資料中包含「陣列」形式的資料,那麼可以使用「點」語法來獲取陣列:
```php
$name = $request->input('products.0.name');
$names = $request->input('products.*.name');
```
### 從查詢字串獲取輸入
使用 `input`, `inputs` 方法可以從整個請求中獲取輸入資料(包括 `Query 引數`),而 `query(?string $key = null, $default = null)` 方法可以只從查詢字串中獲取輸入資料:
```php
// 存在則返回,不存在則返回 null
$name = $request->query('name');
// 存在則返回,不存在則返回預設值 Hyperf
$name = $request->query('name', 'Hyperf');
// 不傳遞引數則以關聯陣列的形式返回所有 Query 引數
$name = $request->query();
```
### 獲取 `JSON` 輸入資訊
如果請求的 `Body` 資料格式是 `JSON`,則只要 `請求物件(Request)``Content-Type` `Header 值` 正確設定為 `application/json`,就可以通過 `input(string $key, $default = null)` 方法訪問 `JSON` 資料,你甚至可以使用 「點」語法來讀取 `JSON` 陣列:
```php
// 存在則返回,不存在則返回 null
$name = $request->input('user.name');
// 存在則返回,不存在則返回預設值 Hyperf
$name = $request->input('user.name', 'Hyperf');
// 以陣列形式返回所有 Json 資料
$name = $request->all();
```
### 確定是否存在輸入值
要判斷請求是否存在某個值,可以使用 `has($keys)` 方法。如果請求中存在該值則返回 `true`,不存在則返回 `false``$keys` 可以傳遞一個字串,或傳遞一個數組包含多個字串,只有全部存在才會返回 `true`
```php
// 僅判斷單個值
if ($request->has('name')) {
// ...
}
// 同時判斷多個值
if ($request->has(['name', 'email'])) {
// ...
}
```
## Cookies
### 從請求中獲取 Cookies
使用 `getCookieParams()` 方法從請求中獲取所有的 `Cookies`,結果會返回一個關聯陣列。
```php
$cookies = $request->getCookieParams();
```
如果希望獲取某一個 `Cookie` 值,可通過 `cookie(string $key, $default = null)` 方法來獲取對應的值:
```php
// 存在則返回,不存在則返回 null
$name = $request->cookie('name');
// 存在則返回,不存在則返回預設值 Hyperf
$name = $request->cookie('name', 'Hyperf');
```
## 檔案
### 獲取上傳檔案
你可以使用 `file(string $key, $default): ?Hyperf\HttpMessage\Upload\UploadedFile` 方法從請求中獲取上傳的檔案物件。如果上傳的檔案存在則該方法返回一個 `Hyperf\HttpMessage\Upload\UploadedFile` 類的例項,該類繼承了 `PHP``SplFileInfo` 類的同時也提供了各種與檔案互動的方法:
```php
// 存在則返回一個 Hyperf\HttpMessage\Upload\UploadedFile 物件,不存在則返回 null
$file = $request->file('photo');
```
### 檢查檔案是否存在
您可以使用 `hasFile(string $key): bool` 方法確認請求中是否存在檔案:
```php
if ($request->hasFile('photo')) {
// ...
}
```
### 驗證成功上傳
除了檢查上傳的檔案是否存在外,您也可以通過 `isValid(): bool` 方法驗證上傳的檔案是否有效:
```php
if ($request->file('photo')->isValid()) {
// ...
}
```
### 檔案路徑 & 副檔名
`UploadedFile` 類還包含訪問檔案的完整路徑及其副檔名方法。`getExtension()` 方法會根據檔案內容判斷檔案的副檔名。該副檔名可能會和客戶端提供的副檔名不同:
```php
// 該路徑為上傳檔案的臨時路徑
$path = $request->file('photo')->getPath();
// 由於 Swoole 上傳檔案的 tmp_name 並沒有保持檔案原名,所以這個方法已重寫為獲取原檔名的字尾名
$extension = $request->file('photo')->getExtension();
```
### 儲存上傳檔案
上傳的檔案在未手動儲存之前,都是存在一個臨時位置上的,如果您沒有對該檔案進行儲存處理,則在請求結束後會從臨時位置上移除,所以我們可能需要對檔案進行持久化儲存處理,通過 `moveTo(string $targetPath): void` 將臨時檔案移動到 `$targetPath` 位置持久化儲存,程式碼示例如下:
```php
$file = $request->file('photo');
$file->moveTo('/foo/bar.jpg');
// 通過 isMoved(): bool 方法判斷方法是否已移動
if ($file->isMoved()) {
// ...
}
```