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-ControlEtag 头来处理。本指南并不适合完整介绍缓存的功能,但你可以在 Google DevelopersMobify Blog 中了解更多。

默认情况下,所有通过 CodeIgniter 发送的响应都是关闭了 HTTP 缓存的。 但在实际应用中,情况千变万化,无法简单的设置一个合适的默认值,除非关闭它, 不过,可以通过 setCache() 方法设置你需要的缓存的值。这非常简单

$options = [
        'max-age'  => 300,
        's-maxage' => 900,
        'etag'     => 'abcde',
];
$this->response->setCache($options);

$options 是一个简单的键值对数组,它们被分配给 Cache-Control 头。你也可以根据具体情况自由设定所有选项。

虽然大多数选项都应用于 Cache-Control 头,但它会智能地处理 etaglast-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 标头,包括 ETagsLast-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);