安装 Yii2 高级模板
1 2
| composer global require "fxp/composer-asset-plugin:^1.2.0" composer create-project --prefer-dist yiisoft/yii2-app-advanced Api
|
初始化项目
打开文件 common/config/main-local.php
,配置数据库信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php return [ 'components' => [ 'db' => [ 'class' => 'yii\db\Connection', 'dsn' => 'mysql:host=localhost;dbname=api', 'username' => 'root', 'password' => '123456', 'charset' => 'utf8', ], 'mailer' => [ 'class' => 'yii\swiftmailer\Mailer', 'viewPath' => '@common/mail', 'useFileTransport' => true, ], ], ];
|
执行迁移文件,生成数据表
新建模板 api
,执行操作如下:
- 复制目录
frontend
为 api
- 复制目录
environments/dev/frontend
为 environments/dev/api
- 复制目录
environments/prod/frontend
为 environments/prod/api
- 修改目录
api
里面文件的命名空间 namespace
- 打开文件
common/config/bootstrap.php
并加入代码 Yii::setAlias('api', dirname(dirname(__DIR__)) . '/api');
清理模板 api
,删除文件如下:
- api/assets
- api/views
- api/controllers
- api/web/assets
- api/web/css
配置 Apache 虚拟主机
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
| <VirtualHost *:80> ServerName api.frontend.app DocumentRoot "/Users/LuisEdware/Code/Api/frontend/web/" <Directory "/Users/LuisEdware/Code/Api/frontend/web/"> RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . index.php DirectoryIndex index.php Require all granted </Directory> </VirtualHost> <VirtualHost *:80> ServerName api.backend.app DocumentRoot "/Users/LuisEdware/Code/Api/backend/web/" <Directory "/Users/LuisEdware/Code/Api/backend/web/"> RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . index.php DirectoryIndex index.php Require all granted </Directory> </VirtualHost> <VirtualHost *:80> ServerName api.app DocumentRoot "/Users/LuisEdware/Code/Api/api/web/" <Directory "/Users/LuisEdware/Code/Api/api/web/"> RewriteEngine on RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . index.php DirectoryIndex index.php Require all granted </Directory> </VirtualHost>
|
搭建基本的 RESTFul 架构
创建控制器
在目录 api/controllers
下创建控制器 UserController
,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php namespace api\modules\v1\controllers; use yii\rest\ActiveController; class OrderController extends ActiveController { public $modelClass = 'api\modules\v1\models\Order'; public $serializer = [ 'class' => 'yii\rest\Serializer', 'collectionEnvelope' => 'items', ]; }
|
配置路由规则
打开文件 api/config/main-local.php
,在数组 $config['components']
中新增代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php 'components' => [ 'request' => [ 'cookieValidationKey' => 'sTGCwRd3spEa33BW2HMjuuwZnsJO6RMM', 'parsers' => [ 'application/json' => 'yii\web\JsonParser', ], ], 'urlManager' => [ 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'rules' => [ [ 'class' => 'yii\rest\UrlRule', 'controller' => 'user', 'pluralize' => false, ], ], ], ],
|
创建数据模型
在目录 api\models
新增数据模型,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| <?php namespace api\models; use yii\db\ActiveRecord; class User extends ActiveRecord { public static function tableName() { return "user"; } public function fields() { $fields = parent::fields(); unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']); return $fields; } }
|
测试接口地址
使用 HTTP GET
的方式去访问 http://api.app/user
,得到 JSON 数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| { "items": [ { "id": 1, "username": "okirlin", "email": "brady.renner@rutherford.com", "role": 10, "status": 10, "created_at": 1391885313, "updated_at": 1391885313 }, { "id": 2, "username": "troy.becker", "email": "nicolas.dianna@hotmail.com", "role": 10, "status": 0, "created_at": 1391885313, "updated_at": 1391885313 }, { "id": 3, "username": "miles", "email": "506510463@qq.com", "role": 10, "status": 0, "created_at": 1231231233, "updated_at": 1231231233 } ], "_links": { "self": { "href": "http://api.app/user?page=1" } }, "_meta": { "totalCount": 8, "pageCount": 1, "currentPage": 1, "perPage": 20 } }
|
版本控制
实现方式
有两种方案可以实现 API 版本控制:
- 在 URL 中带上请求的版本号,比如:
http://example.com/v1/users
- 把版本号放在HTTP请求头中,通常通过 Accept 头,像这样:
Accept: application/json; version=v1
Yii2 两种方案都支持,官方推荐,使用模块来实现版本化,简化代码维护和管理,在 URL 上带上一个大版本号(比如: v1, v2),在每个大版本中,使用 Accept HTTP
请求头来判定小版本号并编写针对各小版本的条件语句。
创建模块
新建目录 api/modules/v1
,目录下新建文件 Module.php
,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php namespace api\modules\v1; class Module extends \yii\base\Module { public $controllerNamespace = 'api\modules\v1\controllers'; public function init() { parent::init(); } }
|
创建控制器
新建目录 api/modules/v1/controllers
,在该目录下新增控制器 OrderController.php
,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| <?php namespace api\modules\v1\controllers; use yii\rest\ActiveController; class OrderController extends ActiveController { public $modelClass = 'api\modules\v1\models\Order'; public $serializer = [ 'class' => 'yii\rest\Serializer', 'collectionEnvelope' => 'items', ]; }
|
创建模型
新建目录 api/modules/v1/models
,在该目录下新增数据模型 Order.php
,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| <?php namespace api\modules\v1\models; use yii\db\ActiveRecord; class Order extends ActiveRecord { public static function tableName() { return "z_order"; } public function fields() { return [ 'id', 'orderNumber' => 'orderno' ]; } }
|
配置路由与模块
打开文件 api/config/main-local.php
,在数组 $config[]
新增模块版本,在数组 $config['components']['urlManager']['rules']
新增路由规则,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| <?php $config = [ 'modules' => [ 'v1' => [ 'class' => 'api\modules\v1\Module', ], ], 'components' => [ 'request' => [ 'cookieValidationKey' => 'sTGCwRd3spEa33BW2HMjuuwZnsJO6RMM', 'parsers' => [ 'application/json' => 'yii\web\JsonParser', ], ], 'urlManager' => [ 'enablePrettyUrl' => true, 'enableStrictParsing' => true, 'showScriptName' => false, 'rules' => [ [ 'class' => 'yii\rest\UrlRule', 'controller' => 'user', 'pluralize' => false, ], [ 'class' => 'yii\rest\UrlRule', 'controller' => 'v1/order', 'pluralize' => false, ], ], ], ], ];
|
测试接口地址
使用 HTTP GET
的方式去访问 http://api.app/v1/order
,得到 JSON 数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| { "orders": [ { "id": 57, "orderNumber": "201310140001" }, { "id": 68, "orderNumber": "201310150001" }, { "id": 69, "orderNumber": "201310150002" }, { "id": 70, "orderNumber": "201310150003" }, { "id": 71, "orderNumber": "201310170001" }, { "id": 72, "orderNumber": "201310170002" }, { "id": 73, "orderNumber": "201310170003" }, { "id": 74, "orderNumber": "201310170004" }, ] }
|
API 认证
Yii 2 有三种认证用户的验证方式
HttpBasicAuth::className()
:是通过弹窗填用户名密码,默认只需要在用户名栏填入 Access-Token
返回接口数据。
HttpBearerAuth::className()
:是通过请求 Headers
带上 Authorization: Bearer Access-Token
参数返回接口数据。
QueryParamAuth::className()
:是通过 URL
带上 ?access-token=Access-Token
参数返回接口数据。
采用 QueryParamAuth
方式进行验证,因为 RESTFul API
是无状态的,不能通过 session
或 cookie
来保持状态,在模块文件 Module.php
中修改代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| <?php namespace api\modules\v1; use Yii; class Module extends \yii\base\Module { public $controllerNamespace = 'api\modules\v1\controllers'; public function init() { parent::init(); Yii::$app->user->enableSession = false; } public function behaviors() { $behaviors = parent::behaviors(); $behaviors['authenticator'] = [ 'class' => QueryParamAuth::className(), ]; return $behaviors; } }
|
使用 HTTP GET
的方式去访问 http://api.app/v1/order?access-token=HelloWorld
,得到 JSON 数据如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| { "orders": [ { "id": 57, "orderNumber": "201310140001" }, { "id": 68, "orderNumber": "201310150001" }, { "id": 69, "orderNumber": "201310150002" }, { "id": 70, "orderNumber": "201310150003" }, ] }
|
使用 Swagger 生成 API 可调试文档
配置 Swagger-UI
执行以下命令,将 Swagger-UI
克隆到 api/web/v1/
文件夹下:
1 2 3 4
| cd api/web mkdir v1 cd v1 git clone https://github.com/swagger-api/swagger-ui.git
|
执行以下命令,在目录 api/web/v1
下生成 Swagger
文档配置文件:
1 2
| mkdir -p swagger-document/ vim swagger-document/swagger.json
|
打开文件 api/web/v1/swagger-ui/dist/index.html
,修改生成文档的配置文件地址:
1 2 3 4 5
| if (url && url.length > 1) { url = decodeURIComponent(url[1]); } else { url = "http://api.app/v1/swagger-document/swagger.json"; }
|
Swagger-PHP 的基本语法
参考文档
红色为必写的字段,蓝色为封装的字段。
- @SWG\Swagger
- swagger
- info: @SWG\Info
- host - 接口域名
- basePath - 接口前缀路径
- schemes: [“http”, “https”, “ws”, “wss”]
- consumes - 请求 Mime Types
- produces - 响应 Mime Types
- paths: @SWG\Path
- @SWG\Info
- title - 文档标题
- description - 文档描述
- termsOfService - 所属团队
- contact: @SWG\Contact - 联系方式
- @SWG\Contact
- url - 联系链接
- name - 联系名称
- email - 联系邮箱
- @SWG\License
- @SWG\Path
- get: @SWG\Get - HTTP Get 请求
- put: @SWG\Put - HTTP Put 请求
- post: @SWG\Post - HTTP Post 请求
- delete: @SWG\Delete - HTTP Delete 请求
- options: @SWG\Options - HTTP Options 请求
- @SWG\GET
- tags - 请求分类
- summary - 请求简介
- description - 请求描述
- operationId - 请求编号,要求唯一
- consumes - 请求 Mime Types
- produces - 响应 Mime Types
- parameters: @SWG\Parameter - 请求参数
- responses: @SWG\Response - 请求响应
- schemes: [“http”,”https”,”ws”,”wss”] - 请求协议
- deprecated - 是否弃用
- @SWG\Parameter
- name - 请求参数名称
- in: [“query”,”header”,”path”,”formData”,”body”] - 请求参数存放方式
- description - 请求参数描述
- required - 是否要求
- schema - 当
in
为 body
时可以使用,用于描述参数
- type: [“string”, “number”, “integer”, “boolean”, “array”, “file”] - 请求参数类型
- format: [“int32”, “int64”, “float”, “double”, “byte”, “date”, “date-time”] - 请求参数格式
- allowEmptyValue - 是否允许空值
- items - 当
type
为 array
,items
为 required
,描述参数数组
- collectionFormat
- default - 请求参数默认值
- @SWG\Response
- default
- response object
- description - 响应描述
- schema: @SWG\Schema
- headers: @SWG\Header - 响应头部
- example: @SWG\Example - 响应数据例子
- reference object
- $ref
- HTTP Status Code
- response object
- description
- schema: @SWG\Schema
- headers: @SWG\Header
- example: @SWG\Example
- reference object
- $ref
- @SWG\Definition
- definition
- required
- @SWG\Property
- @SWG\Property
- property - 模型成员属性
- type: [“string”, “number”, “integer”, “boolean”, “array”, “file”] - 模型参数类型
- format: [“int32”, “int64”, “float”, “double”, “byte”, “date”, “date-time”] - 模型参数格式
- @SWG\Header
- header - 头部名称
- type - 头部数值类型
- description - 头部简介
配置 Swagger-PHP
使用 Composer
安装 Swagger-PHP
,在项目根目录中执行命令如下:
1
| composer require zircote/swagger-php
|
在 api\controllers
新增文档控制器 DocumentController.php
,因为要生成不同版本的文档,控制器必须放在公用的目录,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| <?php namespace api\controllers; use Yii; use Swagger; use yii\base\Exception; use yii\web\Controller; class DocumentController extends Controller { public function actionBuild($version) { $apiDir = Yii::getAlias('@api'); $swagger = Swagger\scan($apiDir); $jsonFile = $apiDir . "/web/{$version}/swagger-document/swagger.json"; if (!file_exists($jsonFile)) { throw new Exception("Swagger.json 文件不存在"); } $isWrite = file_put_contents($jsonFile, $swagger); if ($isWrite == true) { $this->redirect("/{$version}/swagger-ui/dist/index.html"); } else { throw new Exception("Swagger.json 文件写入失败"); } } }
|
新增路由如下:
1 2 3 4 5 6
| <?php [ 'class' => 'yii\web\UrlRule', 'pattern' => 'document/build/<version:\w+>', 'route' => 'document/build', ],
|
模块文件 app/modules/Module.php
新增注释如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
|
|
Yii 2 的 RESTFul APT 会自动为控制器提供六个动作如:index
、view
、create
、update
、delete
、options
,给控制器 app/v1/controlelr/OrderController.php
新增以下注释,为其生成接口文档。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
|
|
打开控制器 app/modules/v1/controller/UserController.php
,继承 actions() 方法,修改 user/create
的场景,并添加 user/create
文档生成注释代码,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135
| <?php namespace api\modules\v1\controllers; use yii\rest\ActiveController; class UserController extends ActiveController { public $modelClass = 'api\models\User'; public $serializer = [ 'class' => 'yii\rest\Serializer', 'collectionEnvelope' => 'items', ]; public function actions() { $actions = parent::actions(); $actions['create']['scenario'] = 'createScenario'; return $actions; } }
|
打开文件 app/modules/v1/models/User.php
,新增代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?php public function rules() { return [ [ [ 'username', 'auth_key', 'password_hash', 'password_reset_token', 'email', 'role', 'status', 'created_at', 'updated_at', 'access_token', ], 'required', 'on' => ['createScenario'], ] ]; }
|
在 ap1/modules/v1
下新增控制器 MenuController.php
,新增模型 Menu.php
,配置好路由,控制器和模型代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| <?php namespace api\modules\v1\controllers; use yii\rest\ActiveController; class MenuController extends ActiveController { public $modelClass = 'api\modules\v1\models\Menu'; public $serializer = [ 'class' => 'yii\rest\Serializer', 'collectionEnvelope' => 'items', ]; public function actions() { $actions = parent::actions(); $actions['create']['scenario'] = 'createScenario'; return $actions; } }
|
模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| <?php namespace api\modules\v1\models; use yii\db\ActiveRecord; class Menu extends ActiveRecord { public static function tableName() { return "menu"; } public function fields() { return [ 'id', 'name', 'route', ]; } public function rules() { return [ [ [ 'name', 'parent', 'route', 'order', 'data', ], 'required', 'on' => ['createScenario'], ], ]; } }
|
在浏览器中打开 URL: http://api.app/document/build/v1
生成文档。
API 授权
现在已经解决了 RESTFUL API 的脚手架、版本化、API 验证和 API 文档生成的问题,接下来我们来完成 API 授权功能。
首先我们需要建立授权数据,而所有授权数据相关的任务如下:
- 定义角色和权限;
- 建立角色和权限的关系;
- 定义规则;
- 将规则与角色和权限作关联;
- 指派角色给用户。
我们先配置所需的组件,我们使用 Yii2 自带 RBAC 组件进行权限控制,打开配置文件 api/config/main.php
,在数组 components
新增代码如下:
1 2 3
| 'authManager' => [ 'class' => 'yii\rbac\DbManager', ],
|
然后在根目录执行命令,在数据库创建好相关的数据表,执行命令如下:
1
| php yii migrate --migrationPath=@yii/rbac/migrations
|
在项目根目录 console/controllers
文件夹新建控制器 RbacController.php
,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| <?php namespace console\controllers; use Yii; use yii\console\Controller; class RbacController extends Controller { public function actionInit() { $authManager = Yii::$app->authManager; $createMenu = $authManager->createPermission('menu/create'); $createMenu->description = 'Create a Menu'; $authManager->add($createPost); $updateMenu = $authManager->createPermission('menu/update'); $updateMenu->description = 'Update Menu'; $authManager->add($updateMenu); $author = $authManager->createRole('author'); $authManager->add($author); $authManager->addChild($author, $createPost); $admin = $authManager->createRole('admin'); $authManager->add($admin); $authManager->addChild($admin, $updatePost); $authManager->addChild($admin, $author); $authManager->assign($admin, 1); $authManager->assign($author, 2); } }
|
然后在根目录中执行命令 php yii rbac/init
,填充 RBAC 的测试数据,并在文件 v1/Module.php
中更改代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| <?php public function behaviors() { $behaviors = parent::behaviors(); $behaviors['authenticator'] = [ 'class' => QueryParamAuth::className(), ]; Yii::$app->user->setIdentity(User::findIdentityByAccessToken(Yii::$app->request->get('access-token'))); $operation = Yii::$app->controller->id . '/' . Yii::$app->controller->action->id; if (!Yii::$app->user->can($operation)) { echo '没有' . $operation . '的操作权限'; } }
|
编写测试
如果是 RESTFul API 的架构,我会选择编写 API 测试和单元测试。首先先从 API 测试开始。首先在 api
中创建 API 测试配置文件,执行命令如下:
1
| codecept generate:suite api
|
进入文件夹api/tests
,打开文件 api.suite.yml
,编写配置如下:
1 2 3 4 5 6 7 8 9
| class_name: ApiTester modules: enabled: [PhpBrowser, REST] config: PhpBrowser: url: http://api.app REST: url: http://api.app depends: PhpBrowser
|
在文件夹 api
生成 API 测试文件,执行命令如下:
1 2
| codecept generate:cept api/v1 SearchMenu codecept generate:cept api/v1 CreateMenu
|
打开文件 api/tests/api/v1/SearchMenuCept.php
,编写代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php use api\tests\ApiTester; use Codeception\Util\HttpCode; $I = new ApiTester($scenario); $I->wantTo('search menus'); $I->haveHttpHeader('Content-Type', 'application/json'); $I->sendGet('/v1/menu', ['access-token' => "HelloWorld"]); $I->seeResponseCodeIs(HttpCode::OK); $I->seeResponseIsJson(); $I->seeResponseMatchesJsonType([ 'items' => 'array', '_links' => 'array', '_meta' => [ 'totalCount' => 'integer', 'pageCount' => 'integer', 'currentPage' => 'integer', 'perPage' => 'integer', ], ]);
|
打开文件 api/tests/api/v1/CreateMenuCept.php
,编写代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?php use api\tests\ApiTester; $I = new ApiTester($scenario); $I->wantTo('create menu'); $I->haveHttpHeader('Content-Type', 'application/json'); $I->sendPOST('/v1/menu?access-token=HelloWorld', [ 'name' => '歪理兔', 'parent' => '1', 'route' => '/go/to/very-to', 'order' => 0, 'data' => 'hello', ]); $I->seeResponseCodeIs(201); $I->seeResponseIsJson(); $I->seeResponseMatchesJsonType([ 'id' => 'integer', 'name' => 'string', 'route' => 'string', ]);
|
接着构建测试环境,并运行所编写的 API 测试,执行命令如下:
1 2
| codecept build codecept run
|
错误处理
Yii 2 的 REST 框架的 HTTP 状态代码如下:
- 200: OK。一切正常。
- 201: 响应 POST 请求时成功创建一个资源。Location header 包含的URL指向新创建的资源。
- 204: 该请求被成功处理,响应不包含正文内容 (类似 DELETE 请求)。
- 304: 资源没有被修改。可以使用缓存的版本。
- 400: 错误的请求。可能通过用户方面的多种原因引起的,例如在请求体内有无效的JSON 数据,无效的操作参数,等等。
- 401: 验证失败。
- 403: 已经经过身份验证的用户不允许访问指定的 API 末端。
- 404: 所请求的资源不存在。
- 405: 不被允许的方法。 请检查 Allow header 允许的HTTP方法。
- 415: 不支持的媒体类型。 所请求的内容类型或版本号是无效的。
- 422: 数据验证失败 (例如,响应一个 POST 请求)。 请检查响应体内详细的错误消息。
- 429: 请求过多。 由于限速请求被拒绝。
- 500: 内部服务器错误。 这可能是由于内部程序错误引起的。
对应的 class 使用如下:
- BadRequestHttpException - 400
- UnauthorizedHttpException - 401
- ForbiddenHttpException - 403
- NotFoundHttpException - 404
- MethodNotAllowedHttpException - 405
- UnsupportedMediaTypeHttpException - 415
- UnprocessableEntityHttpException - 422
- TooManyRequestsHttpException - 429
- ServerErrorHttpException - 500