Response 响应对象
Response 对象封装了 Swoole HTTP 响应(Swoole\Http\Response),提供状态码、响应头、Cookie、JSON/HTML 内容输出、重定向、文件发送等能力,所有修改类方法均支持链式调用,并支持注入 ResponseInterface 类型或通过静态门面(Facade)调用。
处理器返回值处理规则
控制器方法(含闭包路由)的返回值由框架统一处理(源码 HttpEventHandle::handleResponse()),这是最常用的输出方式:
| 返回类型 | 处理方式 |
|---|---|
ResponseInterface 实例 | 直接调用其 send() 发送,不再重复包装 |
| 数组或对象 | 自动 JSON 编码(json())后发送 |
其他类型(含 null) | 转为字符串作为响应体发送 |
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 实例
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) | self | JSON 编码并设为响应体,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 | 设置响应体内容 |
// 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 响应。
状态码
// 签名
status(int $http_status_code, string $reasonPhrase = ''): self状态码有效范围为 100-599,越界抛出 InvalidArgumentException;$reasonPhrase 省略时自动从 Status 常量取对应描述。setStatusCode() 是它的别名。
use Viswoole\HttpServer\Status;
return $response
->status(Status::CREATED)
->json(['id' => 1, 'message' => '创建成功']);Viswoole\HttpServer\Status 以常量定义了全部标准状态码,常用如下:
| 常量 | 值 | 说明 |
|---|---|---|
Status::OK | 200 | 成功 |
Status::CREATED | 201 | 创建成功 |
Status::NO_CONTENT | 204 | 无内容 |
Status::MOVED_PERMANENTLY | 301 | 永久重定向 |
Status::FOUND | 302 | 临时重定向 |
Status::BAD_REQUEST | 400 | 请求错误 |
Status::UNAUTHORIZED | 401 | 未认证 |
Status::FORBIDDEN | 403 | 禁止访问 |
Status::NOT_FOUND | 404 | 资源不存在 |
Status::METHOD_NOT_ALLOWED | 405 | 方法不允许 |
Status::UNPROCESSABLE_ENTITY | 422 | 语义错误无法处理 |
Status::INTERNAL_SERVER_ERROR | 500 | 服务器内部错误 |
Status::getReasonPhrase($code) 可查询任意状态码的描述短语,未收录时返回 Unknown。
响应头
| 方法 | 返回值 | 说明 |
|---|---|---|
header(string $key, string $value, bool $format = true) | self | 设置单个响应头,$format 控制是否按 HTTP 约定格式化键名 |
setHeader(string $key, string $value, bool $format = true) | self | header() 的别名 |
setHeaders(array $headers) | self | 批量设置,数组值自动以逗号拼接 |
getHeader() | array | 获取全部已设置的响应头 |
trailer(string $key, string $value) | bool | 在响应末尾追加 Trailer 标头,仅 HTTP/2 有效 |
return $response
->setHeaders([
'Cache-Control' => 'no-store',
'X-Request-Id' => 'req-1001',
])
->json($data);响应已结束或已分离后设置标头会抛出 InvalidArgumentException。标头名称与值会经 Header::validate() 校验,拦截空值与换行符(CRLF 注入)。
Cookie
cookie() 的值会经过 URL 编码,rawCookie() 不编码(适合 JWT 等原始值),两者参数一致:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| key | string | 必填 | Cookie 名称 |
| value | string | '' | Cookie 值 |
| expire | int | 0 | 过期时间戳,0 表示会话结束 |
| path | string | '/' | 有效路径 |
| domain | string | '' | 有效域名 |
| secure | bool | false | 是否仅通过 HTTPS 传输 |
| httponly | bool | false | 是否禁止 JS 读取 |
| samesite | string | '' | SameSite 策略(如 Strict、Lax) |
| priority | string | '' | 优先级 |
// 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);重定向
// 签名
redirect(string $uri, int $http_code = 302): bool调用即发送响应(无需再 send())。301 永久重定向需显式传状态码:
public function oldEntry(ResponseInterface $response): bool
{
return $response->redirect('/new-entry', 301);
}发送文件
// 签名
sendfile(string $filePath, int $offset = 0, int $length = 0, ?string $fileMimeType = null): bool| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| filePath | string | 必填 | 文件绝对路径,不存在时抛 InvalidArgumentException |
| offset | int | 0 | 起始偏移量(字节) |
| length | int | 0 | 发送长度,0 表示发送至文件末尾 |
| fileMimeType | string|null | null | MIME 类型,null 时用 finfo 自动检测,失败回退 application/octet-stream |
底层使用 Swoole 零拷贝发送,适合大文件下载:
return $response
->header('Content-Disposition', 'attachment; filename="report.pdf"')
->sendfile('/runtime/reports/report.pdf');输出控制
| 方法 | 返回值 | 说明 |
|---|---|---|
end(?string $content = null) | bool | 结束响应并发送内容,null 时发送已设置的内容 |
send(?string $content = null) | bool | end() 的别名 |
write(string $data) | self | HTTP Chunk 分段写入,用于流式输出 |
isWritable() | bool | 响应是否仍可写入(未结束且未分离) |
detach() | self | 分离响应对象,销毁时不再自动 end,配合 create() 实现异步推送 |
echo(bool $echo = true) | self | 调试用:响应内容同时输出到控制台(含耗时) |
// 分段输出大体积 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 都会被忽略。要么返回值交给框架发送,要么方法内自行完成发送。
底层对象与工厂方法
Response::getSwooleResponse(); // \Swoole\Http\Response
// 工厂方法:创建新响应对象(需先 detach 旧响应,否则同一请求会发送两次响应)
$newResponse = Response::create($server, $fd);Response 同样实现了魔术代理,未定义的属性/方法调用会转发到底层 Swoole\Http\Response。
相关阅读
- Request 请求对象:与响应配套的请求读取 API
- 创建控制器:返回值处理规则的上下文
- 中间件:在响应阶段统一加工输出
