HTTP 响应
Response 类通过只适合服务器对调用它的客户端做出响应的方法来扩展 HTTP 消息类 。
使用响应
一个 Response 类实例会为你实例化并传入控制器中。它可以通过 $this->response
访问。许多时候你不需要直接接触该类,因为 CodeIgniter 会为你发送 header 和 body。如果页面成功地创建了它被要求的内容,情况就是这样。当事情出错时,或者你需要发送非常具体的状态码回应,或者利用 HTTP 缓存的强大功能,它就为你提供了这些。
设置输出
当你需要直接设置脚本的输出,而不依赖于 CodeIgniter 自动获取时,你可以用 setBody
方法手动设置。这通常与设置响应的状态码一起使用:
<?php
$this->response->setStatusCode(404)->setBody($body);
原因短语(“OK”、“Created”、“Moved Permanently”)将被自动添加,但你可以在 setStatusCode()
方法的第二个参数中添加自定义原因:
<?php
$this->response->setStatusCode(404, 'Nope. Not here.');
你可以将一个数组格式化为 JSON 或 XML,并通过 setJSON
和 setXML
方法将 content type header 设置为适当的 MIME 类型。通常,你会传递一个数据数组进行转换:
<?php
$data = [
'success' => true,
'id' => 123,
];
return $this->response->setJSON($data);
// or
return $this->response->setXML($data);
设置标题
你经常需要为响应设置标题。Response 类使得这非常简单,通过 setHeader()
方法。第一个参数是标题的名称。第二个参数是值,可以是字符串或在发送到客户端时将正确组合的字符串数组。与使用原生 PHP 函数相比,使用这些函数可以确保标题不会过早发送,从而造成错误,并使测试成为可能。
<?php
$this->response->setHeader('Location', 'http://example.com')
->setHeader('WWW-Authenticate', 'Negotiate');
如果标题已经存在且可以有多个值,则可以使用 appendHeader()
和 prependHeader()
方法将值添加到值列表的末尾或开头。第一个参数是标题名称,第二个参数是要追加或前置的价值。
<?php
$this->response->setHeader('Cache-Control', 'no-cache')
->appendHeader('Cache-Control', 'must-revalidate');
可以使用 removeHeader()
方法从响应中删除标题,该方法仅将标题名称作为唯一参数。这不区分大小写。
<?php
$this->response->removeHeader('Location');
重定向
如果你想要创建一个重定向,请使用 redirect()
函数。
它将返回一个 RedirectResponse
实例。
重要
如果你想要重定向,必须在 Controller
或 Controller Filter 的方法中返回 RedirectResponse
实例。
请注意, __construct()
或 initController()
方法不能返回任何值。
如果你忘记返回 RedirectResponse
,将不会发生重定向。
重定向到一个 URI 路径
当你想传递一个 URI 路径(相对于 baseURL)时,使用 redirect()->to()
:
// Go to specific URI path. "admin/home" is the URI path relative to baseURL.
return redirect()->to('admin/home');
备注
如果你的 URL 中有一个你想要删除的片段,你可以在该方法中使用 refresh 参数。
就像 return redirect()->to('admin/home', null, 'refresh');
一样。
重定向到定义的路由
当你想传递一个 路由名称 或 Controller::method
进行 反向路由 时,使用 redirect()->route()
:
// Go to a named route. "user_gallery" is the route name, not a URI path.
return redirect()->route('user_gallery');
当将参数传递到函数中时,它被视为路由名称或 Controller::method 进行反向路由,而不是相对/完整 URI,
它的处理方式与使用 redirect()->route()
相同:
// Go to a named/reverse-routed URI.
return redirect('named_route');
重定向回上一页面
当你想要重定向回上一页面时,使用 redirect()->back()
:
// Go back to the previous page.
return redirect()->back();
// Keep the old input values upon redirect so they can be used by the `old()` function.
return redirect()->back()->withInput();
// Set a flash message.
return redirect()->back()->with('foo', 'message');
// Copies all cookies from global response instance.
return redirect()->back()->withCookies();
// Copies all headers from the global response instance.
return redirect()->back()->withHeaders();
备注
redirect()->back()
与浏览器的“后退”按钮不同。
当 Session 可用时,它会将访问者带到“在 Session 期间查看的最后一页”。
如果没有加载 Session,或者 Session 不可用,那么将使用 HTTP_REFERER 的安全版本。
重定向状态码
GET 请求的默认 HTTP 状态码是 302。但是,当使用 HTTP/1.1 或更高版本时,对于 POST/PUT/DELETE 请求使用 303,对于所有其他请求使用 307。
你可以指定状态码:
// Redirect to a URI path relative to baseURL with status code 301.
return redirect()->to('admin/home', 301);
// Redirect to a route with status code 308.
return redirect()->route('user_gallery', [], 308);
// Redirect back with status code 302.
return redirect()->back(302);
备注
由于一个错误,在 v4.3.3 或更早版本中,即使指定了状态码, 实际重定向响应的状态码也可能被改变。 请参阅 ChangeLog v4.3.4。
如果你不知道重定向的 HTTP 状态码,建议阅读 Redirections in HTTP。
强制文件下载
Response 类提供了一种简单的方法来将文件发送给客户端,提示浏览器下载数据到计算机。这会设置适当的头使其发生。
第一个参数是**希望下载的文件的名称**,第二个参数是文件数据。
如果将第二个参数设置为 null,且 $filename
是一个存在的可读文件路径,
则将读取其内容。
如果将第三个参数设置为布尔值 true,那么将发送实际的基于文件名扩展名的文件 MIME 类型, 所以如果浏览器有该类型的处理程序,就可以使用它。
示例:
<?php
$data = 'Here is some text!';
$name = 'mytext.txt';
return $this->response->download($name, $data);
如果你想从服务器下载现有文件,你需要为第二个参数显式传递 null
:
<?php
// Contents of photo.jpg will be automatically read
return $this->response->download('/path/to/photo.jpg', null);
使用可选的 setFileName()
方法可以更改发送到客户端浏览器的文件名:
<?php
return $this->response->download('awkwardEncryptedFileName.fakeExt', null)->setFileName('expenses.csv');
备注
必须返回响应对象以便下载被发送到客户端。这允许在被发送到客户端之前通过所有的 after 过滤器来传递响应。
HTTP 缓存
内置于 HTTP 规范的是帮助客户端(通常是网页浏览器)缓存结果的工具。如果使用正确,这可以为你的应用程序带来巨大的性能提升,因为它会告诉客户端他们不需要联系服务器,因为没有变化。你再也找不到更快的了。
这是通过 Cache-Control
和 ETag
头处理的。本指南不是适合对所有缓存头功能进行透彻的介绍,但是你可以在 Google Developers 上很好地理解它。
默认情况下,通过 CodeIgniter 发送的所有响应对象都关闭了 HTTP 缓存。由于我们无法创建一个好的默认值,除了关闭它之外的选项太多了。根据你的需要设置缓存值非常简单,可以通过 setCache()
方法完成:
<?php
$options = [
'max-age' => 300,
's-maxage' => 900,
'etag' => 'abcde',
];
$this->response->setCache($options);
$options
数组简单地以 key/value 对的形式获取通常分配给 Cache-Control
头的数组。你可以自由地根据具体情况完全设置所需的所有选项。虽然大多数选项应用于 Cache-Control
头,但它也智能地处理 etag
和 last-modified
选项到适当的头。
内容安全策略
防止站点遭受 XSS 攻击的最佳保护之一是在站点上实现内容安全策略。这会强制你列出站点 HTML 中拉入的每一个内容源,包括图像、样式表、javascript 文件等。浏览器将拒绝不符合白名单的内容源。这个白名单在响应的 Content-Security-Policy
头中创建,可以用多种不同的方式进行配置。
这听起来很复杂,在一些网站上,确实可能具有挑战性。但是,对于许多简单的网站来说,其中所有内容都由同一域服务(http://example.com), integrating 它非常简单。
由于这是一个复杂的主题,本用户指南不会详细介绍所有细节。欲了解更多信息,你应访问以下网站:
打开 CSP
重要
Debug 工具栏 可能使用 Kint,它 输出内联脚本。因此,打开 CSP 时,Debug 工具栏的 CSP nonce 将自动输出。 但是,如果你不使用 CSP nonce,这将改变 CSP 头以实现你不打算的方式, 它的行为与生产环境不同;如果你想验证 CSP 的行为,请关闭 Debug 工具栏。
默认情况下,不支持此功能。要在应用程序中启用支持,请编辑 app/Config/App.php 中的 CSPEnabled
值:
<?php
namespace Config;
use CodeIgniter\Config\BaseConfig;
class App extends BaseConfig
{
public bool $CSPEnabled = true;
// ...
}
启用后,响应对象将包含 CodeIgniter\HTTP\ContentSecurityPolicy
的一个实例。
app/Config/ContentSecurityPolicy.php 中设置的值将应用于该实例,如果运行时不需要更改,那么格式正确的头将被发送,你就完成了。
启用 CSP 后,会向 HTTP 响应添加两行头:一个是 Content-Security-Policy 头,其中包含策略以标识在不同上下文中明确允许的内容类型或来源;另一个是 Content-Security-Policy-Report-Only 头,它标识将被允许但也将报告给你选择的目标的内容类型或来源。
我们的实现提供了对默认处理的支持,可以通过 reportOnly()
方法更改。
当向 CSP 指令添加额外条目时,如下所示,它将添加到适当的用于阻止或防止的 CSP 头中。这可以在每次调用的基础上通过提供可选的第二个参数来覆盖。
运行时配置
如果你的应用程序需要在运行时进行更改,你可以在控制器中通过 $this->response->getCSP()
访问实例。
该类包含许多与适当的头值映射非常清楚的方法。示例如下,使用不同的组合参数,尽管所有这些“添加”方法都接受指令名称或指令名称数组:
<?php
// get the CSP instance
$csp = $this->response->getCSP();
// specify the default directive treatment
$csp->reportOnly(false);
// specify the origin to use if none provided for a directive
$csp->setDefaultSrc('cdn.example.com');
// specify the URL that "report-only" reports get sent to
$csp->setReportURI('http://example.com/csp/reports');
// specify that HTTP requests be upgraded to HTTPS
$csp->upgradeInsecureRequests(true);
// add types or origins to CSP directives
// assuming that the default treatment is to block rather than just report
$csp->addBaseURI('example.com', true); // report only
$csp->addChildSrc('https://youtube.com'); // blocked
$csp->addConnectSrc('https://*.facebook.com', false); // blocked
$csp->addFontSrc('fonts.example.com');
$csp->addFormAction('self');
$csp->addFrameAncestor('none', true); // report this one
$csp->addImageSrc('cdn.example.com');
$csp->addMediaSrc('cdn.example.com');
$csp->addManifestSrc('cdn.example.com');
$csp->addObjectSrc('cdn.example.com', false); // reject from here
$csp->addPluginType('application/pdf', false); // reject this media type
$csp->addScriptSrc('scripts.example.com', true); // allow but report requests from here
$csp->addStyleSrc('css.example.com');
$csp->addSandbox(['allow-forms', 'allow-scripts']);
每个“添加”方法的第一个参数是一个适当的字符串值或值数组。
reportOnly()
方法允许你为后续源指定默认报告处理,除非被覆盖。例如,你可以指定 youtube.com 被允许,然后提供几个允许但报告的源:
<?php
// get the CSP instance
$csp = $this->response->getCSP();
$csp->addChildSrc('https://youtube.com'); // allowed
$csp->reportOnly(true);
$csp->addChildSrc('https://metube.com'); // allowed but reported
$csp->addChildSrc('https://ourtube.com', false); // allowed
内联内容
可以将网站设置为不保护自己页面上的内联脚本和样式,因为这可能是用户生成内容的结果。为了防止这种情况,CSP 允许你在 <style>
和 <script>
标签中指定一个 nonce,并将这些值添加到响应的头中。这在实际生活中是一个痛点,但是在代码中生成效果最好。为了简化这一过程,你可以在标签中包含一个 {csp-style-nonce}
或 {csp-script-nonce}
占位符,它将自动为你处理:
// 原始的
<script {csp-script-nonce}>
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// 变为
<script nonce="Eskdikejidojdk978Ad8jf">
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// 或者
<style {csp-style-nonce}>
. . .
</style>
警告
如果攻击者注入类似 <script {csp-script-nonce}>
的字符串,它可能会成为带有这个功能的真正 nonce 属性。你可以在 app/Config/ContentSecurityPolicy.php 中使用 $scriptNonceTag
和 $styleNonceTag
属性自定义占位符字符串。
如果你不喜欢这种自动替换功能,可以在 app/Config/ContentSecurityPolicy.php 中设置 $autoNonce = false
来关闭它。
在这种情况下,你可以使用函数 csp_script_nonce()
和 csp_style_nonce()
// 原始的
<script <?= csp_script_nonce() ?>>
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// 变为
<script nonce="Eskdikejidojdk978Ad8jf">
console.log("Script won't run as it doesn't contain a nonce attribute");
</script>
// 或者
<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()
- class CodeIgniter\HTTP\Response
- getStatusCode()
- 返回
当前 HTTP 状态码
- 返回类型
int
返回当前响应的状态码。如果没有设置状态码,将抛出 BadMethodCallException:
<?php echo $response->getStatusCode();
- setStatusCode($code[, $reason=''])
- 参数
$code (
int
) – HTTP 状态码$reason (
string
) – 可选的原因短语
- 返回
当前的 Response 实例
- 返回类型
CodeIgniter\HTTP\Response
设置应随此响应一起发送的 HTTP 状态码:
<?php $response->setStatusCode(404);
原因短语将根据官方列表自动生成。如果你需要为自定义状态码设置自己的原因短语,可以将原因短语作为第二个参数传递:
<?php $response->setStatusCode(230, 'Tardis initiated');
- getReasonPhrase()
- 返回
当前的原因短语
- 返回类型
string
返回当前状态码的原因短语。如果未设置状态,将返回空字符串:
<?php echo $response->getReasonPhrase();
- setDate($date)
- 参数
$date (
DateTime
) – 带有要为此响应设置时间的 DateTime 实例
- 返回
当前响应实例
- 返回类型
CodeIgniter\HTTP\Response
设置此响应使用的日期。
$date
参数必须是一个DateTime
实例。
- setContentType($mime[, $charset='UTF-8'])
- 参数
$mime (
string
) – 此响应所代表的内容类型$charset (
string
) – 此响应使用的字符集
- 返回
当前响应实例
- 返回类型
CodeIgniter\HTTP\Response
设置此响应所代表的内容类型:
<?php $response->setContentType('text/plain'); $response->setContentType('text/html'); $response->setContentType('application/json');
默认情况下,该方法将字符集设置为
UTF-8
。如果需要更改此设置,可以将字符集作为第二个参数传递:<?php $response->setContentType('text/plain', 'x-pig-latin');
- noCache()
- 返回
当前响应实例
- 返回类型
CodeIgniter\HTTP\Response
设置
Cache-Control
头关闭所有 HTTP 缓存。这是所有响应消息的默认设置:<?php $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 选项时,它可以是日期字符串或 DateTime 对象。
- setLastModified($date)
- 参数
$date (
string|DateTime
) – 要设置 Last-Modified 头的日期
- 返回
当前响应实例
- 返回类型
CodeIgniter\HTTP\Response
设置
Last-Modified
头。$date
对象可以是字符串或DateTime
实例:<?php $response->setLastModified(date('D, d M Y H:i:s')); $response->setLastModified(DateTime::createFromFormat('!U', $timestamp));
- send() Response
- 返回
当前响应实例
- 返回类型
CodeIgniter\HTTP\Response
告诉响应将所有内容发送回客户端。这将首先发送 header,然后是响应 body。对于主应用程序响应,你不需要调用它,因为 CodeIgniter 会自动处理。
- setCookie($name = ''[, $value = ''[, $expire = ''[, $domain = ''[, $path = '/'[, $prefix = ''[, $secure = false[, $httponly = false[, $samesite = null]]]]]]]])
- 参数
$name (
array|Cookie|string
) – Cookie 名称或参数数组或CodeIgniter\Cookie\Cookie
实例$value (
string
) – Cookie 值$expire (
int
) – Cookie 到期时间,以秒为单位。如果设置为0
cookie 将只保持浏览器打开时有效$domain (
string
) – Cookie 域名$path (
string
) – Cookie 路径$prefix (
string
) – Cookie 名称前缀。如果设置为''
,将使用 app/Config/Cookie.php 中的默认值$secure (
bool
) – 是否只通过 HTTPS 传输 cookie。如果设置为null
,将使用 app/Config/Cookie.php 中的默认值$httponly (
bool
) – 是否只将 cookie accessible 用于 HTTP 请求(无 JavaScript)。如果设置为null
,将使用 app/Config/Cookie.php 中的默认值$samesite (
string
) – SameSite cookie 参数的值。如果设置为''
,cookie 将不设置 SameSite 属性。如果设置为null
,将使用 app/Config/Cookie.php 中的默认值
- 返回类型
void
备注
在 v4.2.7 之前版本,由于一个错误,
$secure
和$httponly
的默认值为false
, 从未使用来自 app/Config/Cookie.php 的这些值。使用你指定的值设置 cookie。有两种传递信息的方式以便可以设置 cookie:数组方法和离散参数:
数组方法
使用此方法,关联数组作为第一个参数传递:
<?php $cookie = [ 'name' => 'The Cookie Name', 'value' => 'The Value', 'expire' => '86500', 'domain' => '.some-domain.com', 'path' => '/', 'prefix' => 'myprefix_', 'secure' => true, 'httponly' => false, 'samesite' => 'Lax', ]; $response->setCookie($cookie);
仅
name
和value
是必需的。要删除 cookie,请将expire
置空。expire
以**秒**设置,将添加到当前时间。不要包括时间,而只设置从*现在*希望 cookie 有效的秒数。如果expire
设置为零,cookie 将只在浏览器打开时有效。备注
但是如果同时将
value
设置为空字符串和expire
设置为0
, cookie 将被删除。对于无论如何请求站点的站点范围 cookie,在域名前添加站点 URL,如: .your-domain.com
通常不需要
path
,因为该方法设置根路径。仅在需要避免与服务器上其他同名 cookie 的名称冲突时才需要
prefix
。仅在希望通过设置为
true
将其设置为安全 cookie 时才需要secure
标志。samesite
值控制 cookie 在域和子域之间的共享方式。允许的值是'None'
、'Lax'
、'Strict'
或空字符串''
。 如果设置为空字符串,将设置默认的 SameSite 属性。离散参数
如果你愿意,可以通过传递使用各个参数的数据来设置 cookie:
<?php $response->setCookie($name, $value, $expire, $domain, $path, $prefix, $secure, $httponly, $samesite);
- deleteCookie($name = ''[, $domain = ''[, $path = '/'[, $prefix = '']]])
- 参数
$name (
mixed
) – Cookie 名称或参数数组$domain (
string
) – Cookie 域名$path (
string
) – Cookie 路径$prefix (
string
) – Cookie 名称前缀
- 返回类型
void
删除现有的 cookie。
仅
name
是必需的。仅当需要避免与服务器上其他同名 cookie 的名称冲突时才需要
prefix
。如果希望只删除该子集的 cookie,请提供
prefix
。 如果只希望删除该域的 cookie,请提供domain
名称。 如果只希望删除该路径的 cookie,请提供path
名称。如果任何可选参数为空,则同名的 cookie 将在所有情况下被删除。
例子:
<?php $response->deleteCookie($name);
- hasCookie($name = ''[, $value = null[, $prefix = '']])
- 参数
$name (
mixed
) – Cookie 名称或参数数组$value (
string
) – cookie 值$prefix (
string
) – Cookie 名称前缀
- 返回类型
bool
检查响应是否具有指定的 cookie。
注意
仅
name
是必需的。如果指定了prefix
,它将被添加到 cookie 名称前。如果没有给出
value
,该方法仅检查具有给定名称的 cookie 是否存在。 如果给出value
,则该方法检查具有给定名称和值的 cookie 是否存在。例子:
<?php if ($response->hasCookie($name)) { // ... }
- getCookie($name = ''[, $prefix = ''])
- 参数
$name (
string
) – Cookie 名称$prefix (
string
) – Cookie 名称前缀
- 返回类型
Cookie|Cookie[]|null
如果找到,返回指定的 cookie,否则返回
null
。 如果没有给出name
,则返回Cookie
对象数组。例子:
<?php $cookie = $response->getCookie($name);
- getCookies()
- 返回类型
Cookie[]
返回当前在 Response 实例中设置的所有 cookie。 这些是你在当前请求期间明确指定要设置的任何 cookie。