Http 生命周期
了解请求生命周期, 有利于理解HTTP服务各组件, 编写出更好代码.
配置参数
在应用下的 app/bean.php 配置 server,在这个文件里,你可以看到 Http Server数组里面包含了 Http Server 的基本信息。下面列举了一些简单的配置,你也可以自由组合同时提供多种服务。
'httpServer' => [
'class' => HttpServer::class,
'port' => 18306,
'listener' => [
'rpc' => bean('rpcServer')
],
'process' => [
// 'monitor' => bean(MonitorProcess::class)
// 'crontab' => bean(CrontabProcess::class)
],
'on' => [
// Enable task must task and finish event
SwooleEvent::TASK => bean(TaskListener::class),
SwooleEvent::FINISH => bean(FinishListener::class)
],
/* @see HttpServer::$setting */
'setting' => [
'task_worker_num' => 12,
'task_enable_coroutine' => true,
'worker_num' => 6,
// Enable Https 这个是配置https证书的可以不设置
'ssl_cert_file' => '/my/certs/2288803_www.domain.com.pem',
'ssl_key_file' => '/my/certs/2288803_www.domain.com.key',
]
],
//Enable Https
'type' => SWOOLE_SOCK_TCP | SWOOLE_SSL,
配置项 http server 除了 class 其他都是 http server 的属性。
配置介绍
class 指定 Http Server 的处理类
port 指定 Http Server 的端口
listener 指定其他一同启动的服务,添加端口服务监听,可以多个。
rpc 启动 RPC 服务
process 启动自定义用户进程
on 配置监听的事件 注册事件、设置对应事件的处理监听,事件触发组件调用,在任务里面使用
setting 这里是参考 Swoole Server 配置选项
- pidFile 设置进程 pid 文件 位置,默认值 @runtime/swoft.pid
- mode 运行的模式,参考 Swoole Server 构造函数 第三个参数
- type 指定Socket的类型,支持TCP、UDP、TCP6、UDP6、UnixSocket Stream/Dgram 等 Swoole Server 构造函数 第四个参数
- 启用 Https 支持 注意: 你必须安装 OpenSSL 库,并且确保安装 swoole 时是启用了 ssl 选项的。同时,需要设置 ‘type’ => SWOOLE_SOCK_TCP | SWOOLE_SSL
Controller 控制器
控制器作为HTTP服务的核心组件,串接起一次请求的整个生命周期. 通过 注解 的方式,相较于传统的 Controller,代码更简洁,用户可以更关注业务逻辑。
创建控制器
主要通过 @Controller 注解实现。代码可以放置任意位置,不过为了统一标准,建议放在 app/Http/Controller 下
namespace App\Http\Controller;
use Swoft\Http\Message\ContentType;
use Swoft\Http\Message\Response;
use Swoft\Http\Server\Annotation\Mapping\Controller;
use Swoft\Http\Server\Annotation\Mapping\RequestMapping;
use Swoft\View\Annotation\Mapping\View;
use Throwable;
/**
* Class ViewController
*
* @since 2.0
*
* @Controller(prefix="view")
*/
class ViewController
{
/**
* @RequestMapping("index")
*
* @param Response $response
*
* @return Response
*/
public function index(Response $response): Response
{
$response = $response->withContent('<html lang="en"><h1>Swoft framework</h1></html>');
$response = $response->withContentType(ContentType::HTML);
return $response;
}
}
代码分析
@Controller 注解
Http 控制器类注解 @Controller
注解类:Swoft\Http\Server\Annotation\Mapping\Controller
- 作用范围:CLASS
- 拥有属性:
- prefix 指定路由前缀
通常仅有 @Controller 是没有什么效果的,它需要配合接下来的 @RequestMapping 一起才能正确的工作。
路由规则
显式指定路由前缀:@Controller(prefix=”/index”) 或 @Controller(“/index”)。
隐式指定路由前缀:@Controller() 默认自动使用 小驼峰 格式解析 controller class 的名称。
示例:class IndexController 对应路由 /index
一个完整的路由规则是通过 @Controller + @RequestMapping 注解实现,通常前者定义前缀,后者定义后缀。关于 @RequestMapping 注解将在稍后 路由-@RequestMapping 章节将会详细介绍。
在 Swoft 里不要按照传统的 fpm 框架继承父类控制器的成员属性在其他控制器使用,这种做法是错误的。
错误示范:
/**
* @Controller()
*/
class BaseController
{
protected $num;
}
/**
* @Controller(prefix="/v1/index")
*/
class IndexController extends BaseController
{
/**
* @RequestMapping(route="index")
*/
public function index()
{
$this->num++;
echo $this->num."\n";//这里每次访问输出的都不一样
}
}
此时每次访问num数字都会增1,这个是错误的使用方式,和传统的 php-fpm 有很大区别.传统的 fpm 每次执行过后都会释放内存,而 swoft 是常驻内存的 大家一定要注意
路由
Swoft 与传统的 PHP 框架不一样,并没有采用配置文件的方式来配置路由,而采用了注解。在 Swoft 里我们可以使用 @RequestMapping 注解快速的添加路由。
@RequestMapping 注解
Http 控制器类中方法路由注解 @RequestMapping
- route 路由规则path
- method 请求方式(GET、POST、PUT、PATCH、DELETE、OPTIONS、HEAD)
- params 可以通过它为path变量添加正则匹配限制
每个方法上尽量只写一个 @RequestMapping 注解,以免出现紊乱。
路由规则
通常情况,一个完整的路由 path 等于 @Controller 的 prefix + @RequestMapping 的 route 显示指定路由后缀:@RequestMapping(“index”) 或 @RequestMapping(route=”index”)
隐式指定路由后缀: 使用 @RequestMapping() 默认解析方法名为后缀
特殊的,当你的 @RequestMapping 上的路由以 / 开头时,那完整的路由就是它,即不会再将 prefix 添加到它的前面
允许的请求方法为默认为 GET 和 POST 当设置跨域是需要手动指定允许 OPTIONS
绑定路由 path 参数
指定路由参数: @RequestMapping(route=”index/{name}”),Action 方法中可以直接使用 $name 作为方法参数
当路由参数被 [] 包起来则 URL path 传递参数是可选的。注意,可选符只能用在最后面
- 示例1: @RequestMapping(“/index[/{name}]”) 这样 /index /index/tom 都可以访问到
- 示例2: @RequestMapping(“/about[.html]”) 相当于伪静态,/about /about.html 都可以访问到
设置路由请求方式
如果想要设置允许请求控制器的 HTTP 请求方式。 可以使用方法在控制器中的 @RequestMapping 注解配置 method 参数,可以是 GET、POST、PUT、PATCH、DELETE、OPTIONS、HEAD 中的一个或多个。
@RequestMapping(route="index",method={RequestMethod::GET,RequestMethod::POST})
请切记要引入相关的注解类
Swoft\Http\Server\Annotation\Mapping\RequestMapping
Swoft\Http\Server\Annotation\Mapping\RequestMethod
Http 请求对象
Swoft 的请求与响应实现于 PSR-7 规范。请求与响应对象存在于每次 HTTP 请求。
- 请求对象 Request 为 Swoft\Http\Message\Request
- 响应对象 Response 为 Swoft\Http\Message\Response
获取请求对象
$request = context()->getRequest();
示例: 获取请求的 URI
$uri=$request->getUri();
请求对象的 URI 本身就是一个对象,它提供了下列方法检查 HTTP 请求的 URL 部分
$uri->getScheme()
$uri->getAuthority()
$uri->getUserInfo()
$uri->getHost()
$uri->getPort()
$uri->getPath()
$uri->getQuery() (例如 a=1&b=2)
$uri->getFragment()
示例: 获取请求 Headers
全部的 Headers
$headers = $request->getHeaders();
指定的 Header
$host = $request->getHeaderLine("host");
示例: 获取请求的数据
GET 数据
$data = $request->query();
$some = $request->query('key', 'default value')
$data = $request->get();
$some = $request->get('key','default value');
POST 数据
$data = $request->post();
$some = $request->post('key', 'default value')
无需关心请求的数据格式,json xml 请求都会自动解析为 php 的数组数据。都可以通过 $request->post() 获取。
同时获取 GET & POST 数据
$data = $request->input();
$some = $request->input('key', 'default value')
RAW 数据
$data = $request->raw();
SERVER 数据
$data = $request->getServerParams();
$some = $request->server('key', 'default value')
获取上传文件
$file = $request->getUploadedFiles();
获取的结果是一维数组或者二位数组,数据结构如下。 若表单中上传的是单文件则返回的是一个一维数组,数组内容是 Swoft\Http\Message\Upload\UploadedFile 文件对象,例如文件字段名为 file 则数据结构如下
注意这个 UploadedFile 对象的属性都是私有属性,withdata过滤了私有属性所以直接输出 $file这个对象输出的是个空数组,而不是上传未接受到数据.
获取的结果是一维数组或者二位数组,数据结构如下。 若表单中上传的是单文件则返回的是一个一维数组,数组内容是 Swoft\Http\Message\Upload\UploadedFile 文件对象,例如文件字段名为 file 则数据结构如下
array(1) {
["file"]=>
object(Swoft\Http\Message\Upload\UploadedFile)#6510 (7) {
["size":"Swoft\Http\Message\Upload\UploadedFile":private]=>
int(1319)
["errorCode":"Swoft\Http\Message\Upload\UploadedFile":private]=>
int(0)
["file":"Swoft\Http\Message\Upload\UploadedFile":private]=>
string(25) "/tmp/swoole.upfile.f7p2EL"
["clientFilename":"Swoft\Http\Message\Upload\UploadedFile":private]=>
string(6) "at.png"
["clientMediaType":"Swoft\Http\Message\Upload\UploadedFile":private]=>
string(9) "image/png"
["moved":"Swoft\Http\Message\Upload\UploadedFile":private]=>
NULL
["path":"Swoft\Http\Message\Upload\UploadedFile":private]=>
NULL
}
}
若表单中是一个字段数组上传多个文件如 file[] 则返回的是一个二维数组,数组内容依然是 Swoft\Http\Message\Upload\UploadedFile 文件对象,数据结构如下
array(1) {
["file"]=>
array(2) {
[0]=>
object(Swoft\Http\Message\Upload\UploadedFile)#6516 (7) {
["size":"Swoft\Http\Message\Upload\UploadedFile":private]=>
int(1319)
["errorCode":"Swoft\Http\Message\Upload\UploadedFile":private]=>
int(0)
["file":"Swoft\Http\Message\Upload\UploadedFile":private]=>
string(25) "/tmp/swoole.upfile.TVKdOS"
["clientFilename":"Swoft\Http\Message\Upload\UploadedFile":private]=>
string(6) "at.png"
["clientMediaType":"Swoft\Http\Message\Upload\UploadedFile":private]=>
string(9) "image/png"
["moved":"Swoft\Http\Message\Upload\UploadedFile":private]=>
NULL
["path":"Swoft\Http\Message\Upload\UploadedFile":private]=>
NULL
}
...
}
}
文件操作方法
moveTo() 将上传的文件移动到新位置。
getSize() 获取文件大小,单位 byte。
getError() 获取上传文件相关的错误信息,若无错将必须返回 UPLOAD_ERR_OK 常量,若又错误将返回 UPLOAD_ERR_XXX 相关常量。
getClientFilename() 获取文件上传时客户端本地的文件名,不要相信此方法返回的值。客户端可能会发送恶意虚假文件名,意图破坏或破解您的应用程序。
getClientMediaType() 获取客户端中文件的 MediaType 类型,不要相信此方法返回的值。客户端可能会发送恶意虚假文件名,意图破坏或破解您的应用程序。
其他常用辅助方法
if ($request->isAjax()) {
// Do something
}
if ($request->isGet()) {
// Do something
}
if ($request->isPost()) {
// Do something
}
Http 响应对象
根据 PSR-7 对象的不可变性(immutable),所有的 with* 方法都是克隆对象然后返回,必须接收新对象来做进一步处理,或使用链式调用
例如:
return $response->withContentType(ContentType::HTML)->withContent('<html lang="en"><h1>Swoft framework</h1></html>');
获取响应对象
$response=context()->getResponse()
设置响应状态码
return $response->withStatus(404)
示例: 输出字符串内容响应
return $response->withContent("Hello Swoft2.0");
示例: 输出数组内容响应
$data = ['name'=>'Swoft2.0'];
return $response->withData($data);
示例: 设置响应头信息
return $response->withHeader("name","Swoft2.0");
示例: 重定向
// 302
return $response->redirect("http://www.swoft.org",302);
// 404 page
return $response->redirect('/404');
示例: 文件下载
return $response->file(\alias('@runtime/1.zip'), "application/octet-stream");
示例: 设置 Cookies
$response = $response->withCookie('name', 'value');
$response = $response->withCookie('name', [
'value' => 'value3',
'httpOnly' => true
]);
来源:https://8code.net/index/index/article/id/47