Response 响应对象

Response 对象封装了 Swoole HTTP 响应(Swoole\Http\Response),提供状态码、响应头、Cookie、JSON/HTML 内容输出、重定向、文件发送等能力,所有修改类方法均支持链式调用,并支持注入 ResponseInterface 类型或通过静态门面(Facade)调用。

处理器返回值处理规则

控制器方法(含闭包路由)的返回值由框架统一处理(源码 HttpEventHandle::handleResponse()),这是最常用的输出方式:

返回类型处理方式
ResponseInterface 实例直接调用其 send() 发送,不再重复包装
数组或对象自动 JSON 编码(json())后发送
其他类型(含 null转为字符串作为响应体发送
php
use Viswoole\Router\Annotation\AutoController;

#[AutoController(prefix: 'demo')]
class DemoController
{
    public function array(): array           // 数组 → JSON
    {
        return ['code' => 0, 'message' => 'ok'];
    }

    public function text(): string           // 字符串 → 响应体
    {
        return 'hello';
    }

    public function html(): ResponseInterface // 完全控制响应
    {
        return Response::html('<h1>hello</h1>');
    }
}

仅在响应仍可写入(isWritable())时才会处理返回值。若方法内部已调用 send()/end()/redirect() 等完成发送,响应不可写时返回值会被忽略。

获取 Response 实例

php
use Viswoole\HttpServer\Contract\ResponseInterface;
use Viswoole\HttpServer\Facade\Response;

// 方式一:方法参数类型注入(容器解析,推荐)
public function index(ResponseInterface $response): ResponseInterface
{
    return $response->json(['ok' => true]);
}

// 方式二:静态门面
Response::json(['ok' => true])->send();

// 方式三:从容器获取
$response = app(ResponseInterface::class);

若应用定义了 \App\Response 类(继承框架 Response),HttpService 的绑定会自动指向自定义实现。

快捷响应方法

方法返回值说明
json(mixed $data)selfJSON 编码并设为响应体,Content-Type 设为 application/json
html(string $html)self设置 HTML 响应体,Content-Type 设为 text/html
setContentType(string $contentType, string $charset = 'utf-8')self快捷设置 Content-Type 标头
setContent(string $content)self设置响应体内容
php
// JSON 响应(返回 self,可继续链式设置状态码、响应头)
return $response->json(['code' => 0, 'data' => $list]);

// 纯文本
return $response->setContentType('text/plain')->setContent('ok');

JSON 编码默认使用 JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES(中文与斜杠不转义);编码失败抛出 RuntimeException

默认响应头

Response 实例创建时默认状态码为 200,默认 Content-Type 为 text/html; charset=utf-8,由构造函数同步到底层 Swoole 响应。

状态码

php
// 签名
status(int $http_status_code, string $reasonPhrase = ''): self

状态码有效范围为 100-599,越界抛出 InvalidArgumentException$reasonPhrase 省略时自动从 Status 常量取对应描述。setStatusCode() 是它的别名。

php
use Viswoole\HttpServer\Status;

return $response
    ->status(Status::CREATED)
    ->json(['id' => 1, 'message' => '创建成功']);

Viswoole\HttpServer\Status 以常量定义了全部标准状态码,常用如下:

常量说明
Status::OK200成功
Status::CREATED201创建成功
Status::NO_CONTENT204无内容
Status::MOVED_PERMANENTLY301永久重定向
Status::FOUND302临时重定向
Status::BAD_REQUEST400请求错误
Status::UNAUTHORIZED401未认证
Status::FORBIDDEN403禁止访问
Status::NOT_FOUND404资源不存在
Status::METHOD_NOT_ALLOWED405方法不允许
Status::UNPROCESSABLE_ENTITY422语义错误无法处理
Status::INTERNAL_SERVER_ERROR500服务器内部错误

Status::getReasonPhrase($code) 可查询任意状态码的描述短语,未收录时返回 Unknown

响应头

方法返回值说明
header(string $key, string $value, bool $format = true)self设置单个响应头,$format 控制是否按 HTTP 约定格式化键名
setHeader(string $key, string $value, bool $format = true)selfheader() 的别名
setHeaders(array $headers)self批量设置,数组值自动以逗号拼接
getHeader()array获取全部已设置的响应头
trailer(string $key, string $value)bool在响应末尾追加 Trailer 标头,仅 HTTP/2 有效
php
return $response
    ->setHeaders([
        'Cache-Control' => 'no-store',
        'X-Request-Id'  => 'req-1001',
    ])
    ->json($data);

响应已结束或已分离后设置标头会抛出 InvalidArgumentException。标头名称与值会经 Header::validate() 校验,拦截空值与换行符(CRLF 注入)。

cookie() 的值会经过 URL 编码,rawCookie() 不编码(适合 JWT 等原始值),两者参数一致:

参数类型默认值说明
keystring必填Cookie 名称
valuestring''Cookie 值
expireint0过期时间戳,0 表示会话结束
pathstring'/'有效路径
domainstring''有效域名
secureboolfalse是否仅通过 HTTPS 传输
httponlyboolfalse是否禁止 JS 读取
samesitestring''SameSite 策略(如 StrictLax
prioritystring''优先级
php
// 7 天有效的登录态 Cookie
return $response->cookie(
    key: 'token',
    value: $token,
    expire: time() + 86400 * 7,
    httponly: true,
    secure: true,
    samesite: 'Strict',
);

// 删除 Cookie:过期时间设为过去
return $response->cookie('token', '', time() - 3600);

重定向

php
// 签名
redirect(string $uri, int $http_code = 302): bool

调用即发送响应(无需再 send())。301 永久重定向需显式传状态码:

php
public function oldEntry(ResponseInterface $response): bool
{
    return $response->redirect('/new-entry', 301);
}

发送文件

php
// 签名
sendfile(string $filePath, int $offset = 0, int $length = 0, ?string $fileMimeType = null): bool
参数类型默认值说明
filePathstring必填文件绝对路径,不存在时抛 InvalidArgumentException
offsetint0起始偏移量(字节)
lengthint0发送长度,0 表示发送至文件末尾
fileMimeTypestring|nullnullMIME 类型,null 时用 finfo 自动检测,失败回退 application/octet-stream

底层使用 Swoole 零拷贝发送,适合大文件下载:

php
return $response
    ->header('Content-Disposition', 'attachment; filename="report.pdf"')
    ->sendfile('/runtime/reports/report.pdf');

输出控制

方法返回值说明
end(?string $content = null)bool结束响应并发送内容,null 时发送已设置的内容
send(?string $content = null)boolend() 的别名
write(string $data)selfHTTP Chunk 分段写入,用于流式输出
isWritable()bool响应是否仍可写入(未结束且未分离)
detach()self分离响应对象,销毁时不再自动 end,配合 create() 实现异步推送
echo(bool $echo = true)self调试用:响应内容同时输出到控制台(含耗时)
php
// 分段输出大体积 CSV,避免一次性占用内存
$response->header('Content-Type', 'text/csv');
$response->write("id,name\n");
foreach ($rows as $row) {
    $response->write("{$row['id']},{$row['name']}\n");
}
return $response;

不要手动 end 后再返回内容

end()/send() 调用后响应即不可写,控制器再返回数组或 Response 都会被忽略。要么返回值交给框架发送,要么方法内自行完成发送。

底层对象与工厂方法

php
Response::getSwooleResponse(); // \Swoole\Http\Response

// 工厂方法:创建新响应对象(需先 detach 旧响应,否则同一请求会发送两次响应)
$newResponse = Response::create($server, $fd);

Response 同样实现了魔术代理,未定义的属性/方法调用会转发到底层 Swoole\Http\Response

相关阅读