# 响应
响应需要返回一个 herosphp\core\HttpResponse
对象,为了方便创建这个对象,我们在框架底层做了一层封装,
可以在控制器返回任意类型的数据(数组、字符串、数字,对象...),如果返回对象的话,该对象需要实现 JsonAble
接口。
当然herosphp
提供了一些助手函数。
// response
GF::response(int $code = 200, array $headers = [], mixed $body = ''):HttpResponse;
// redirect
GF::redirect(string $url, int $code = 301): HttpResponse
# 返回一个任意响应
<?php
declare(strict_types=1);
/**
* This file is part of monda-worker.
*
* @contact mondagroup_php@163.com
*/
namespace app\modules\admin\action;
use app\utils\resp\Result;
use herosphp\annotation\Controller;
use herosphp\annotation\Get;
use herosphp\core\BaseController;
use herosphp\core\Config;
#[Controller(name: KeyController::class, desc: '公钥')]
class KeyController extends BaseController
{
#[Get(uri: '/admin/key/publicKey', desc: '获取公钥')]
public function publicKey(): string
{
return Config::get(name:'rsa', key: 'public_key');
}
}
你也可以先创建一个空的response
对象,然后在适当的位置利用$response->cookie()
$response->header()
$response->withHeaders()
$response->withBody()
设置返回内容。
public function hello(): HttpResponse
{
// 创建一个对象
$response = GF::response();
// .... 业务逻辑省略
// 设置cookie
$response->cookie('foo', 'value');
// .... 业务逻辑省略
// 设置http头
$response->header('Content-Type', 'application/json');
$response->withHeaders([
'X-Header-One' => 'Header Value 1',
'X-Header-Tow' => 'Header Value 2',
]);
// .... 业务逻辑省略
// 设置要返回的数据
$response->withBody('返回的数据');
return $response;
}
# 返回 json
<?php
namespace app\controller;
use herosphp\core\BaseController;
use herosphp\annotation\Controller;
use herosphp\annotation\Get;
#[Controller(name: Foo::class, desc: 'Foo')]
class Foo extends BaseController
{
#[Get(uri: '/hello', desc: 'foo')]
public function hello()
{
return $this->json(['code' => 0, 'msg' => 'ok']);
}
}
# 返回视图
新建文件 app/controller/Foo.php
如下
<?php
namespace app\controller;
use herosphp\core\BaseController;
use herosphp\annotation\Controller;
use herosphp\annotation\Get;
#[Controller(name: Foo::class, desc: 'Foo')]
class Foo extends BaseController
{
#[Get(uri: '/hello', desc: 'foo')]
public function hello()
{
return $this->html('foo/hello', ['name' => 'herosphp']);
}
}
新建文件 {BASE_PATH}/default/foo/hello.html
如下
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>herosphpApp</title>
</head>
<body>
hello {$name}
</body>
</html>
# 重定向
<?php
namespace app\controller;
use herosphp\GF;
use herosphp\core\BaseController;
use herosphp\annotation\Controller;
use herosphp\annotation\Get;
#[Controller(name: Foo::class, desc: 'Foo')]
class Foo extends BaseController
{
#[Get(uri: '/hello', desc: 'foo')]
public function hello()
{
return GF::redirect('/user');
}
}
# header 设置
<?php
namespace app\controller;
use herosphp\core\HttpRequest;
use herosphp\GF;
use herosphp\core\BaseController;
#[Controller(name: Foo::class, desc: 'Foo')]
class Foo extends BaseController
{
#[Get(uri: '/hello', desc: 'foo')]
public function hello(HttpRequest $request)
{
return GF::response(200, [
'Content-Type' => 'application/json',
'X-Header-One' => 'Header Value'
],'hello herosphp');
}
}
也可以利用header
和withHeaders
方法来单个或者批量设置 header。
<?php
namespace app\controller;
use herosphp\core\HttpRequest;
use herosphp\GF;
use herosphp\core\BaseController;
#[Controller(name: Foo::class, desc: 'Foo')]
class Foo extends BaseController
{
#[Get(uri: '/hello', desc: 'foo')]
public function hello(HttpRequest $request)
{
return GF::response(body:'hello herosphp')
->header('Content-Type', 'application/json')
->withHeaders([
'X-Header-One' => 'Header Value 1',
'X-Header-Tow' => 'Header Value 2',
]);
}
}
你也可以提前设置 header,最后设置将要返回的数据。
public function hello(HttpRequest $request)
{
// 创建一个对象
$response = GF::response();
// .... 业务逻辑省略
// 设置http头
$response->header('Content-Type', 'application/json');
$response->withHeaders([
'X-Header-One' => 'Header Value 1',
'X-Header-Tow' => 'Header Value 2',
]);
// .... 业务逻辑省略
// 设置要返回的数据
$response->withBody('返回的数据');
return $response;
}
# 设置 cookie
<?php
namespace app\controller;
use herosphp\core\HttpRequest;
use herosphp\GF;
use herosphp\core\BaseController;
use herosphp\core\HttpRequest;
#[Controller(name: Foo::class, desc: 'Foo')]
class Foo extends BaseController
{
#[Get(uri: '/hello', desc: 'foo')]
public function hello(HttpRequest $request)
{
return response(body: 'hello herosphp')
->cookie('foo', 'value');
}
}
你也可以提前设置 cookie,最后设置要返回的数据。
public function hello(HttpRequest $request)
{
// 创建一个对象
$response = GF::response();
// .... 业务逻辑省略
// 设置cookie
$response->cookie('foo', 'value');
// .... 业务逻辑省略
// 设置要返回的数据
$response->withBody('返回的数据');
return $response;
}
cookie 方法完整参数如下:
cookie($name, $value = '', $max_age = 0, $path = '', $domain = '', $secure = false, $http_only = false)
# 返回文件流
<?php
namespace app\controller;
#[Controller(name: Foo::class, desc: 'Foo')]
class Foo extends BaseController
{
#[Get(uri: '/hello', desc: 'foo')]
public function hello(HttpRequest $request)
{
return GF::response()->file(PUBLIC_PATH. '/favicon.ico');
}
}
说明
- Herosphp 支持发送超大文件
- 对于大文件(超过 2M),workerman 不会将整个文件一次性读入内存,而是在合适的时机分段读取文件并发送
- workerman 会根据客户端接收速度来优化文件读取发送速度,保证最快速发送文件的同时将内存占用减少到最低
- 数据发送是非阻塞的,不会影响其它请求处理
- file 方法会自动添加
if-modified-since
头并在下一个请求时检测if-modified-since
头,如果文件未修改则直接返回 304 以便节省带宽 - 发送的文件会自动使用合适的
Content-Type
头发送给浏览器 - 如果文件不存在,会自动转为 404 响应
# 下载文件
<?php
namespace app\controller;
use herosphp\core\HttpRequest as Request;
class Foo
{
public function hello(Request $request)
{
return GF::response()->download(PUBLIC_PATH . '/favicon.ico', '可选的文件名.ico');
}
}
download 方法与 file 方法的区别是 download 方法一般用于下载并保存文件,并且可以设置下载的文件名。download 方法不会检查if-modified-since
头。其它与 file 方法行为一致。
# 获取输出
有些类库是将文件内容直接打印到标准输出的,也就是数据会打印在命令行终端里,并不会发送给浏览器,这时候我们需要通过ob_start();
ob_get_clean();
将数据捕获到一个变量中,再将数据发送给浏览器,例如:
<?php
namespace app\controller;
use herosphp\core\HttpRequest as Request;
class Image
{
public function get(Request $request)
{
// 创建图像
$im = imagecreatetruecolor(120, 20);
$text_color = imagecolorallocate($im, 233, 14, 91);
imagestring($im, 1, 5, 5, 'A Simple Text String', $text_color);
// 开始获取输出
ob_start();
// 输出图像
imagejpeg($im);
// 获得图像内容
$image = ob_get_clean();
// 发送图像
return GF::response(body: $image)->header('Content-Type', 'image/jpeg');
}
}