CodeIgniter4 HTTP 响应
响应类扩展了 HTTP 消息类 ,只适用于服务器返回响应给调用它的客户端。
使用响应类
响应类被实例化并传递到控制器。可以通过 $this->response
访问它。很多时候不需要直接使用它,因为 CodeIgniter 会为你发送标头和正文。 如果一切正常,页面会成功创建被请求的内容。 但是当出现问题时,或者当你需要发送指定的状态码,或者想要使用强大的 HTTP 缓存,可以立即使用它。
设置输出内容
当需要直接设置脚本的输出内容时,不要依赖CodeIgniter来自动获取它,应该手动调用 setBody
方法。通常用于设置响应的状态码。
$this->response->setStatusCode(404)
->setBody($body);
响应中的原因短语 (‘OK’, ‘Created’, ‘Moved Permenantly’) 将被自动添加,但也可以通过为 setStatusCode()
方法设置第二个参数来添加自定义的原因。
$this->response->setStatusCode(404, 'Nope. Not here.');
设置 HTTP 头
通常,你需要为响应设置 HTTP 头。响应类通过 setHeader()
方法简化了这个操作。
setHeader()
方法的第一个参数是 HTTP 头的名称,第二个参数是值,它可以是字符串或值的数组,当发送到客户端时将被正确组合。
使用这些函数而不是使用PHP原生函数,可以确保不会过早发送 HTTP 头导致错误,并使测试成为可能。
$response->setHeader('Location', 'http://example.com')
->setHeader('WWW-Authenticate', 'Negotiate');
如果 HTTP 头已经存在并且可以有多个值,可以使用 appendHeader()
prependHeader()
方法分别将值添加到值列表的结尾或开头。
第一个参数是 HTTP 头的名称,第二个参数是添加到结尾或开头的值。
$response->setHeader('Cache-Control', 'no-cache')
->appendHeader('Cache-Control', 'must-revalidate');
HTTP 头可以用 removeHeader()
方法移除,此方法只接受 HTTP 头的名称作为唯一参数。并且不区分大小写。
$response->removeHeader('Location');
文件下载
响应类提供了一个简单地将文件发送给客户端的方法,提示浏览器下载文件。会设置适当的标题来实现。
第一个参数是 下载文件的名称,第二个参数是文件内容。
如果将第二个参数设为 NULL, 并且 $filename
是一个已存在的,可读的文件路径,那么将会使用这个路径下的内容作为文件内容。
如果将第三个参数设置为布尔值 TRUE,那么实际的文件的 MIME 类型(基于文件扩展名)将被发送,这样当浏览器拥有该类型的处理程序 - 可以使用到它。
示例:
$data = 'Here is some text!';
$name = 'mytext.txt';
$response->download($name, $data);
如果要从服务器下载现有的文件,你需要这样做:
// photo.jpg 的内容将被自动读取
$response->download('/path/to/photo.jpg', NULL);
HTTP 缓存
内置的 HTTP 规范是帮助客户端(通常是web浏览器)缓存结果的工具。
正确使用它,可以为应用程序带来巨大的性能提升,因为它会告诉客户端不需要联系服务器,因为没有任何改变。你不会比这更快。
这些都通过 Cache-Control
和 Etag
头来处理。本指南并不适合完整介绍缓存的功能,但你可以在 Google Developers 和 Mobify Blog 中了解更多。
默认情况下,所有通过 CodeIgniter 发送的响应都是关闭了 HTTP 缓存的。 但在实际应用中,情况千变万化,无法简单的设置一个合适的默认值,除非关闭它, 不过,可以通过 setCache()
方法设置你需要的缓存的值。这非常简单
$options = [
'max-age' => 300,
's-maxage' => 900,
'etag' => 'abcde',
];
$this->response->setCache($options);
$options
是一个简单的键值对数组,它们被分配给 Cache-Control
头。你也可以根据具体情况自由设定所有选项。
虽然大多数选项都应用于 Cache-Control
头,但它会智能地处理 etag
和 last-modified
选项到适当的头。
内容安全策略(CSP)
对XSS攻击的最佳保护方式之一是在站点上实施内容安全策略。
这迫使你将从你网站的 HTML 中载入的每一个内容来源列入白名单中,包括图片,样式表,JavaScript文件等。浏览器将拒绝白名单外的的内容。这个白名单在响应的 Content-Security-Policy
标头中创建,并且有多种配置方式。
这听起来很复杂,在某些网站上肯定会有挑战性。对于很多简单的网站,所有的内容由相同的域名(http://example.com)提供,整合起来非常简单。
由于这是一个复杂的主题,本用户指南将不会覆盖所有细节。有关更多信息,你应该访问以下网站:
启用CSP
默认情况下,CSP策略是禁用的。想要在应用程序中启用CSP,修改 application/Config/App.php 中的 CSPEnabled
的值
public $CSPEnabled = true;
当开启后,响应对象将包含一个 CodeIgniter\HTTP\ContentSecurityPolicy
的实例。
在 application/Config/ContentSecurityPolicy.php 中设置的值应用于这个实例,如果在运行时没有修改,那么将会发送正确的格式化后的标题,并且完成所有操作。
运行时配置
如果你的应用需要在运行时进行更改,则可以访问 $response->CSP
实例。该类拥有很多方法,可以很清晰地映射到你需要设置的 header 头
$reportOnly = true;
$response->CSP->reportOnly($reportOnly);
$response->CSP->setBaseURI('example.com', true);
$response->CSP->setDefaultSrc('cdn.example.com', $reportOnly);
$response->CSP->setReportURI('http://example.com/csp/reports');
$response->CSP->setSandbox(true, ['allow-forms', 'allow-scripts']);
$response->CSP->upgradeInsecureRequests(true);
$response->CSP->addChildSrc('https://youtube.com', $reportOnly);
$response->CSP->addConnectSrc('https://*.facebook.com', $reportOnly);
$response->CSP->addFontSrc('fonts.example.com', $reportOnly);
$response->CSP->addFormAction('self', $reportOnly);
$response->CSP->addFrameAncestor('none', $reportOnly);
$response->CSP->addImageSrc('cdn.example.com', $reportOnly);
$response->CSP->addMediaSrc('cdn.example.com', $reportOnly);
$response->CSP->addObjectSrc('cdn.example.com', $reportOnly);
$response->CSP->addPluginType('application/pdf', $reportOnly);
$response->CSP->addScriptSrc('scripts.example.com', $reportOnly);
$response->CSP->addStyleSrc('css.example.com', $reportOnly);
内联内容
可以设置一个网站不保护自己的页面上的内联脚本和样式,因为这可能是用户生成的内容的结果。 为了防止这种情况,CSP 允许你再 <style> 和 <script> 标记中指定一个随机数,并将这些值添加到响应头中。 这样处理很痛苦,但是却是最安全的。 为了简单起见,你可以在代码中包含 {csp-style-nonce} 或 {csp-script-nonce} 占位符,程序将会自动为你处理
// Original
<script {csp-script-nonce}>
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// Becomes
<script nonce="Eskdikejidojdk978Ad8jf">
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// OR
<style {csp-style-nonce}>
. . .
</style>
类参考
注解
除了这里列出的方法,响应类还继承了 消息类 的方法。
父类提供的可用的方法:
CodeIgniter\HTTP\Message::body()
CodeIgniter\HTTP\Message::setBody()
CodeIgniter\HTTP\Message::populateHeaders()
CodeIgniter\HTTP\Message::headers()
CodeIgniter\HTTP\Message::header()
CodeIgniter\HTTP\Message::headerLine()
CodeIgniter\HTTP\Message::setHeader()
CodeIgniter\HTTP\Message::removeHeader()
CodeIgniter\HTTP\Message::appendHeader()
CodeIgniter\HTTP\Message::protocolVersion()
CodeIgniter\HTTP\Message::setProtocolVersion()
CodeIgniter\HTTP\Message::negotiateMedia()
CodeIgniter\HTTP\Message::negotiateCharset()
CodeIgniter\HTTP\Message::negotiateEncoding()
CodeIgniter\HTTP\Message::negotiateLanguage()
CodeIgniter\HTTP\Message::negotiateLanguage()
CodeIgniter\HTTP\Response
statusCode
()
返回: | 此次响应的 HTTP 状态码 |
---|---|
返回类型: | int |
返回此响应的当前状态码,如果没有设置状态码,则会抛出 BadMethodCallException 异常。:
echo $response->statusCode();
setStatusCode
($code[, $reason=''])
参数: | $code (int) – HTTP 状态码 |
---|---|
$reason (string) – 一个可选的原因短语 | |
返回: | 当前的响应实例 |
返回类型: | CodeIgniter\HTTP\Response |
设置此次响应的 HTTP 状态码
$response->setStatusCode(404);
原因短语将会根据协议规定自动的生成。如果你需要为自定义状态码设置自己的愿意短语,你可以将原因短语作为第二个参数传递
$response->setStatusCode(230, "Tardis initiated");
reason
()
返回: | 当前的原因短语。 |
---|---|
返回类型: | string |
返回此响应的当前状态码。如果没有设置状态,将返回一个空字符串
echo $response->reason();
setDate
($date)
参数: | $date (DateTime) – 一个设置了此响应的时间的 DateTime 实例。 |
---|---|
返回: | 当前的响应类实例 |
返回类型: | CodeIgniter\HTTP\Response |
设置响应的时间。 $date
参数必须是一个 DateTime
实例
$date = DateTime::createFromFormat('j-M-Y', '15-Feb-2016');
$response->setDate($date);
setContentType
($mime[, $charset='UTF-8'])
参数: | $mime (string) – 响应的内容类型 |
---|---|
$charset (string) – 此响应使用的字符集。 | |
返回: | 当前的响应类实例 |
返回类型: | CodeIgniter\HTTP\Response |
设置此响应的内容类型
$response->setContentType('text/plain');
$response->setContentType('text/html');
$response->setContentType('application/json');
默认情况下,该方法将字符集设置为 UTF-8
。如果你需要修改,可以将字符集作为第二个参数传递
$response->setContentType('text/plain', 'x-pig-latin');
noCache
()
返回: | 当前的响应类实例 |
---|---|
返回类型: | CodeIgniter\HTTP\Response |
设置 Cache-Control
标头来关闭所有的 HTTP 缓存。这是所有响应消息的默认设置
$response->noCache();
// Sets the following header:
Cache-Control: no-store, max-age=0, no-cache
setCache
($options)
参数: | $options (array) – 一组缓存设置的键值 |
---|---|
返回: | 当前的响应类实例 |
返回类型: | CodeIgniter\HTTP\Response |
设置 Cache-Control
标头,包括 ETags
和 Last-Modified
。 典型的键有:
- etag
- last-modified
- max-age
- s-maxage
- private
- public
- must-revalidate
- proxy-revalidate
- no-transform
当设置了 last-modified 选项时,它的值可以是一个 date 字符串,或一个 DateTime 对象。
setLastModified
($date)
参数: | $date (string/DateTime) – 设置 Last-Modified 的时间 |
---|---|
返回: | 当前的响应类实例 |
返回类型: | CodeIgniter\HTTP\Response |
设置 Last-Modified
头。 $date
可以是一个字符串或一个 DateTime
实例
$response->setLastModified(date('D, d M Y H:i:s'));
$response->setLastModified(DateTime::createFromFormat('u', $time));
send
()
返回: | 当前的响应类实例 |
---|---|
返回类型: | CodeIgniter\HTTP\Response |
通知响应类发送内容给客户端。这将首先发送 HTTP 头,然后是响应的主体内容。对于主应用程序的响应,你不需要调用它,因为它由 CodeIgniter 自动处理。
setCookie
($name = ''[, $value = ''[, $expire = ''[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = FALSE[, $httponly = FALSE]]]]]]])
参数: | $name (mixed) – Cookie 名称或参数数组 |
---|---|
$value (string) – Cookie 值 | |
$expire (int) – Cookie 过期时间,单位:秒 | |
$domain (string) – Cookie 作用域 | |
$path (string) – Cookie 可用的路径 | |
$prefix (string) – Cookie 前缀 | |
$secure (bool) – 是否只通过 HTTPS 传输 Cookie | |
$httponly (bool) – 是否只允许 HTTP 请求读取cookie,JavaScript不可以读取 | |
返回类型: | void |
设置一个包含你指定的值的 Cookie 。有两种将信息传递给该方法的方式:数组和独立参数:
数组方式
使用此方法,将关联数组传递给第一个参数
$cookie = array(
'name' => 'The Cookie Name',
'value' => 'The Value',
'expire' => '86500',
'domain' => '.some-domain.com',
'path' => '/',
'prefix' => 'myprefix_',
'secure' => TRUE
);
$response->setCookie($cookie);
注意事项
只需要名称和值。要删除 Cookie ,将其设置为过期即可。
过期时间使用 秒数 , 将从当前时间开始计算。
不要设置为一个具体的时间,而只是从 now 开始的你希望 Cookie 有效的秒数。
如果过期时间设置为零,Cookie 将只在浏览器打开时有效,浏览器关闭时则被清除。
对于整站的 Cookie , 无论你的网站是被如何请求的,请将你的网址添加到到 domain 中并且以 . 开始,例如: .your-domain.com
通常不需要该路径,因为默认已经设置了根目录。
仅当你需要避免与服务器的其他相同命名的 Cookie 冲突时,才需要前缀。
仅当你想要加密 Cookie 时才需要设置 secure 项为 TRUE。
独立参数
如果你愿意,也可以使用单个参数传递数据来设置 Cookie。
$response->setCookie($name, $value, $expire, $domain, $path, $prefix, $secure);