鍍金池/ 教程/ PHP/ 如何定制錯(cuò)誤頁
如何以非繼承方式自定義方法
如何創(chuàng)建事件監(jiān)聽器
如何以非繼承方式擴(kuò)展一個(gè)類
如何記錄消息到不同的文件
如何掌握并創(chuàng)建新的環(huán)境
如何使用 Doctrine DBAL
"XXX is deprecated" E-USER-DEPRECATED 的警告是什么意思?
在登錄表單中使用 CSRF 保護(hù)
如何注冊(cè)自定義 DQL 函數(shù)
如何為表單類配置空數(shù)據(jù)
如何嵌入集合表單
如何創(chuàng)建自定義認(rèn)證提供者
如何使用 Apache Router
如何組織配置文件
部署在 Microsoft Azure 云
如何在路由參數(shù)中允許"/"字符
如何在安全,路由,服務(wù)和驗(yàn)證中使用表達(dá)式
如何對(duì)顯示控制臺(tái)信息配置 Monolog
如何為一個(gè) Bundle 創(chuàng)建友好的配置
如何改變默認(rèn)的目標(biāo)路徑行為
如何在運(yùn)行測(cè)試之前自定義引導(dǎo)過程
如何從路由向控制器傳輸額外的信息
如何從數(shù)據(jù)庫(實(shí)體提供者)讀取安全用戶
如何從 Controller 調(diào)用一個(gè)命令
如何創(chuàng)建自定義表單密碼驗(yàn)證器
如何使用內(nèi)建的 PHP Web 服務(wù)器
如何在功能測(cè)試中用 Token 模擬認(rèn)證
配置 Session 文件的保存目錄
理解前端控制器、內(nèi)核及環(huán)境如何協(xié)同工作
如何實(shí)現(xiàn)一個(gè)簡單的注冊(cè)表單
如何使用 Doctrine 擴(kuò)展:Timestampable, Sluggable, Translatable 等等
如何使用多個(gè)實(shí)體管理器和連接
如何自定義表單渲染
如何安裝第三方 Bundles
使用預(yù)認(rèn)證安全防火墻
如何簡化多個(gè) Bundle 的配置
會(huì)話代理實(shí)例
安裝 Composer
如何冒充一個(gè)用戶
如何注冊(cè)一個(gè)新的請(qǐng)求格式和 MIME 類型
如何在功能測(cè)試中使用分析器
如何在服務(wù)容器內(nèi)設(shè)置外部參數(shù)
如何重寫 Symfony 默認(rèn)的目錄結(jié)構(gòu)
如何在一個(gè) Symfony 控制器中創(chuàng)建一個(gè) SOAP 的 Web 服務(wù)
如何使用序列化
部署在 Platform.sh
升級(jí)一個(gè)副版本
如何寫一個(gè)自定義的 Twig 擴(kuò)展
如何在 SubVersion 中創(chuàng)建并保存一個(gè) Symfony 項(xiàng)目
使用 PHP 庫聯(lián)合,編譯和最小化 Web 資產(chǎn)
如何創(chuàng)建一個(gè)自定義的數(shù)據(jù)收集器
如何使用和注冊(cè)命名空間路徑
如何使用 Monolog 記錄日志
如何建立一個(gè)傳統(tǒng)的登錄表單
如何強(qiáng)制路由總是使用 HTTPS 或者 HTTP
如何在模板中使用 PHP 而不是 Twig
如何動(dòng)態(tài)選擇密碼加密算法
避免匿名用戶開始 Session 會(huì)話
如何測(cè)試 Doctrine 倉庫
如何在功能測(cè)試中測(cè)試一封電子郵件被發(fā)送
Symfony2 與 Symfony1 的區(qū)別
使用結(jié)尾反斜線重定向 URL
(configuration)如何在數(shù)據(jù)庫中使用 PdoSessionHandler 存儲(chǔ) Sessions
如何使用匹配器有條件地啟用分析器
部署在 Heroku 云
如何不用自定義控制器配置重定向
如何在 Bundle 內(nèi)部加載服務(wù)配置
如何處理不同的錯(cuò)誤級(jí)別
如何在應(yīng)用中保護(hù)服務(wù)和方法
如何對(duì)表單單元測(cè)試
如何把命令定義為服務(wù)
如何配置 Monolog 從日志中排除 404 錯(cuò)誤
如何使用控制臺(tái)
如何測(cè)試與數(shù)據(jù)庫交互的代碼
如何在路由中使用除了 GET 和 POST 的 HTTP 方法
如何使用云服務(wù)發(fā)送電子郵件
如何創(chuàng)建一個(gè)控制臺(tái)命令
在遺留的應(yīng)用上使用 Symfony Session
如何使用高級(jí)的訪問控制列表
如何不用一個(gè)自定義的控制器渲染一個(gè)模板
如何重寫部分 Bundle
升級(jí)一個(gè)主版本
安全訪問控制是如何工作的
如何使用 Bundle 的繼承來重寫部分 Bundle
如何使用 Voter 檢查用戶權(quán)限
如何為多個(gè) Doctrine 的實(shí)現(xiàn)提供模型類
如何使用作用域
如何部署一個(gè) Symfony 應(yīng)用
如何用 "inherit-data" 減少代碼冗余
如何注冊(cè)事件監(jiān)聽器和訂閱
使用 Bower 安裝 Symfony
如何創(chuàng)建一個(gè)自定義路由加載器
如何創(chuàng)建一個(gè)自定義的驗(yàn)證限制
在獨(dú)立注入類中使用參數(shù)
如何使用 Assetic 和 Twig Functions 進(jìn)行圖像優(yōu)化
如何利用表單事件動(dòng)態(tài)修改表單
如何在過濾器的前后設(shè)置事件分發(fā)器
如何在 Bundle 中使用 Compiler Passes
緩存包含 CSRF 保護(hù)表單的頁面
如何注入變量到所有的模板(如全局變量)
如何創(chuàng)建一個(gè)自定義表單域類型
如何限定防火墻使其只允許通過指定請(qǐng)求
如何把 Controller 定義為服務(wù)
如何使用 Gmail 發(fā)送郵件
升級(jí)一個(gè)補(bǔ)丁版本
如何創(chuàng)建一個(gè)表單類型擴(kuò)展
如何對(duì)不同的 URL 強(qiáng)制使用 HTTPS 或者 HTTP
如何使用 Varnish 加速我的 Web 站點(diǎn)
如何定義虛擬類和接口之間的關(guān)系
如何自定義登錄表單
如何測(cè)試多個(gè)客戶端的交互
PSR-7 Bridge
如何使用 YUI Compressor 裁剪 Javascripts 和 Stylesheets
在用戶的 Session 中使用局部 "Sticky"
如何定制錯(cuò)誤頁
如何從已存在的數(shù)據(jù)庫中生成實(shí)體
如何用 Doctrine 上傳文件
可復(fù)用 Bundles 的最佳實(shí)踐
如何發(fā)送一封電子郵件
如何將 Assetic Filter 應(yīng)用到具體的文件擴(kuò)展名上
切換分析器存儲(chǔ)
如何上傳文件
限制 Session 元數(shù)據(jù)的寫入
如何使用多用戶提供者
如何使用數(shù)據(jù)轉(zhuǎn)換
配置一個(gè) Web 服務(wù)器
如何編程訪問分析器數(shù)據(jù)
如何在路由中使用服務(wù)容器參數(shù)
如何在控制臺(tái)生成 URL 和發(fā)送郵件
如何將你的開發(fā)環(huán)境優(yōu)化為調(diào)試環(huán)境
如何在控制臺(tái)命令中啟用日志
如何在功能測(cè)試中模擬 HTTP 認(rèn)證
如何使用 API 驗(yàn)證用戶
如何移除 AcmeDemoBundle
控制臺(tái)命令
如何配置 Symfony 使其工作在負(fù)載均衡和反轉(zhuǎn)代理
如何添加“記住我”登錄功能
如何使用 Assetic 進(jìn)行資產(chǎn)管理
如何限定防火墻使其接受指定主機(jī)
如何使用訪問控制列表(ACLs)
如何裁剪 CSS/JS 文件(使用 UglifyJS 和 UglifyCSS)
如何緩存電子郵件
如何使用 submit() 函數(shù)處理表單提交
如何在 Git 中創(chuàng)建并保存一個(gè) Symfony 項(xiàng)目
如何創(chuàng)建自定義用戶提供者
如何對(duì)電子郵件錯(cuò)誤配置 Monolog
如何在開發(fā)時(shí)使用電子郵件

如何定制錯(cuò)誤頁

在 Symfony 應(yīng)用程序中,所有的錯(cuò)誤都會(huì)被認(rèn)為是異常,不論只是一個(gè) 404 Not Found 錯(cuò)誤還是你的代碼中的一些異常引起的重大錯(cuò)誤。

開發(fā)環(huán)境中,Symfony 緩存所有的異常并且通過一個(gè)擁有很多調(diào)試信息的異常頁來幫助你發(fā)現(xiàn)問題的根源:

http://wiki.jikexueyuan.com/project/symfony-cookbook/images/exceptions-in-dev-environment.png" alt="" />

由于這個(gè)頁面包含了很多敏感的內(nèi)部信息,Symfony 不會(huì)將其在產(chǎn)品環(huán)境中展示。作為替代,它只會(huì)展示一個(gè)普通的簡單的錯(cuò)誤頁

http://wiki.jikexueyuan.com/project/symfony-cookbook/images/errors-in-prod-environment.png" alt="" />

產(chǎn)品環(huán)境下產(chǎn)生的錯(cuò)誤頁可以按照你的要求進(jìn)行不同方式的定制:

  1. 如果你想要改變你的錯(cuò)誤頁的內(nèi)容和風(fēng)格來適應(yīng)你的應(yīng)用程序,那么就重寫默認(rèn)錯(cuò)誤頁模板;

  2. 如果你想要引入 Symfony 使用的邏輯來產(chǎn)生錯(cuò)誤頁,那么就重寫默認(rèn)異??刂破?/a>;

  3. 如果你需要完全控制異常處理執(zhí)行你自己的邏輯,那么使用 kernel.exception 事件。

重寫默認(rèn)錯(cuò)誤頁模板

當(dāng)加載錯(cuò)誤頁的時(shí)候,內(nèi)部的 ExceptionController 被用來產(chǎn)生一個(gè) Twig 模板給用戶顯示。

這個(gè)控制器使用的是 HTTP 狀態(tài)代碼,請(qǐng)求格式和下列邏輯決定了模板文件名:

  1. 找一個(gè)給定的格式和狀態(tài)代碼的模板(就像 error404.json.twig 或者 error500.html.twig);

  2. 如果不存在以前的模板,拋棄狀態(tài)代碼尋找給定格式的一般的模板(就像 error.json.twig 或者 error.xml.twig);

  3. 如果上述所說的模板都不存在,那就用普通的 HTML 模板(error.html.twig)。

為了重寫這些模板,簡單的依靠標(biāo)準(zhǔn)的 Symfony 的重寫 bundle 內(nèi)部的模板的方法:將它們放到 app/Resources/TwigBundle/views/Exception/ 目錄。

典型的工程返回的 HTML 和 JSON 頁面,可能像下面那樣:

app/
└─ Resources/
   └─ TwigBundle/
      └─ views/
         └─ Exception/
            ├─ error404.html.twig
            ├─ error403.html.twig
            ├─ error.html.twig      # All other HTML errors (including 500)
            ├─ error404.json.twig
            ├─ error403.json.twig
            └─ error.json.twig      # All other JSON errors (including 500)

404 錯(cuò)誤模板的例子

將 404 錯(cuò)誤模板重寫成 HTML 頁,創(chuàng)建一個(gè)位于 app/Resources/TwigBundle/views/Exception/ 的新的 error404.html.twig 模板:

{# app/Resources/TwigBundle/views/Exception/error404.html.twig #}
{% extends 'base.html.twig' %}

{% block body %}
    <h1>Page not found</h1>

    {# example security usage, see below #}
    {% if app.user and is_granted('IS_AUTHENTICATED_FULLY') %}
        {# ... #}
    {% endif %}

    <p>
        The requested page couldn't be located. Checkout for any URL
        misspelling or <a href="{{ path('homepage') }}">return to the homepage</a>.
    </p>
{% endblock %}

萬一你需要它們,ExceptionController 通過分別儲(chǔ)存在 HTTP 狀態(tài)代碼和信息中的 status_codestatus_text 變量向錯(cuò)誤頁傳遞一些信息。

你可以通過執(zhí)行 HttpExceptionInterface 來定制狀態(tài)代碼并且需要 getStatusCode() 方法。除此之外,status_code 將會(huì)默認(rèn)成 500。

在開發(fā)環(huán)境中展示的異常頁可以和錯(cuò)誤頁一樣被自定義。為標(biāo)準(zhǔn)的 HTML 異常頁創(chuàng)建一個(gè)新的 exception.html.twig 模板或者為 JSON 異常頁創(chuàng)建一個(gè) exception.json.twig。

當(dāng)在錯(cuò)誤模板中使用安全功能時(shí)避免異常出現(xiàn)

自定義設(shè)計(jì)模板時(shí)的最常見的一個(gè)誤區(qū)就是在錯(cuò)誤模板(或者是其它錯(cuò)誤模板所繼承的模板)中使用 is_granted() 功能。如果你那樣做了,你將會(huì)看到 Symfony 出現(xiàn)異常。

這個(gè)問題的原因就是路由在安全層之前完成了。如果 404 錯(cuò)誤出現(xiàn),安全層不能夠加載并且因此 is_granted() 功能未定義。解決方法就是在使用這個(gè)功能之前添加下列的檢查:

{% if app.user and is_granted('...') %}
    {# ... #}
{% endif %}

在開發(fā)環(huán)境測(cè)試錯(cuò)誤頁

當(dāng)你在開發(fā)環(huán)境的時(shí)候,Symfony 將會(huì)展示出一個(gè)大大的異常頁而不是你新的自定義錯(cuò)誤頁。所以,你如何看到錯(cuò)誤頁長什么樣子并且調(diào)試它呢?

推薦的解決方法就是使用名為 WebfactoryExceptionsBundle 的第三方 bundle。這個(gè) bundle 提供了一個(gè)特殊的測(cè)試控制器可以允許你以任意的 HTTP 狀態(tài)代碼顯示自定義的錯(cuò)誤頁甚至當(dāng) kernel.debug 設(shè)置為 true 也可以。

在開發(fā)環(huán)境測(cè)試錯(cuò)誤頁

默認(rèn)的 ExceptionController 也允許在開發(fā)環(huán)境下預(yù)覽你的錯(cuò)誤頁。

這個(gè)特征是在 Symfony 2.6 中引進(jìn)的,在以前,第三方的 bundle WebfactoryExceptionsBundle 可以起到相同的作用。

使用這一特征,你需要在你的 routing_dev.yml 中進(jìn)行如下定義:

YAML:

# app/config/routing_dev.yml
_errors:
    resource: "@TwigBundle/Resources/config/routing/errors.xml"
    prefix:   /_error

XML:

<!-- app/config/routing_dev.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<routes xmlns="http://symfony.com/schema/routing"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://symfony.com/schema/routing
        http://symfony.com/schema/routing/routing-1.0.xsd">

    <import resource="@TwigBundle/Resources/config/routing/errors.xml"
        prefix="/_error" />
</routes>

PHP:

// app/config/routing_dev.php
use Symfony\Component\Routing\RouteCollection;

$collection = new RouteCollection();
$collection->addCollection(
    $loader->import('@TwigBundle/Resources/config/routing/errors.xml')
);
$collection->addPrefix("/_error");

return $collection;

如果你是用老版本的 Symfony,你可能需要像你的 routing_dev.yml 文件中添加這個(gè)。如果你是從 scratch 開始的,那么 Symfony 標(biāo)準(zhǔn)版本已經(jīng)包含這個(gè)了。

添加了這條路徑,你可以像以下那樣使用網(wǎng)址來用給定的 HTML 狀態(tài)代碼或者給定的狀態(tài)代碼和格式預(yù)覽錯(cuò)誤頁:

http://localhost/app_dev.php/_error/{statusCode}
http://localhost/app_dev.php/_error/{statusCode}.{format}

重寫默認(rèn)的 ExceptionController

如果你需要更多的,超出僅僅重寫模板的靈活性,那么你可以改變產(chǎn)生錯(cuò)誤頁的控制器。舉例來說,你可能需要向你的模板中傳遞一些附加變量。

為了完成這個(gè),在你的應(yīng)用程序的任意的地方創(chuàng)建一個(gè)新的控制器并且設(shè)置 twig.exception_controller 配置選項(xiàng)來指向它:

YAML:

# app/config/config.yml
twig:
    exception_controller:  AppBundle:Exception:showException

XML:

<!-- app/config/config.xml -->
<?xml version="1.0" encoding="UTF-8" ?>
<container xmlns="http://symfony.com/schema/dic/services"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:twig="http://symfony.com/schema/dic/twig"
    xsi:schemaLocation="http://symfony.com/schema/dic/services
        http://symfony.com/schema/dic/services/services-1.0.xsd
        http://symfony.com/schema/dic/twig
        http://symfony.com/schema/dic/twig/twig-1.0.xsd">

    <twig:config>
        <twig:exception-controller>AppBundle:Exception:showException</twig:exception-controller>
    </twig:config>
</container>

PHP:

// app/config/config.php
$container->loadFromExtension('twig', array(
    'exception_controller' => 'AppBundle:Exception:showException',
    // ...
));

TwigBundle 使用的 ExceptionListener 類作為 kernel.exception 事件的監(jiān)聽器創(chuàng)建了會(huì)發(fā)送到你的控制器的請(qǐng)求。除此之外,你的控制器還會(huì)被傳遞兩個(gè)參數(shù):

exception 由被處理的異常所創(chuàng)建的 FlattenException 實(shí)例。

logger 一個(gè)在默認(rèn)環(huán)境下可能為DebugLoggerInterface 實(shí)例。

代替創(chuàng)建你能從 scratch 創(chuàng)建的新的異??刂破?,當(dāng)然,也可以擴(kuò)展默認(rèn)的 ExceptionController。這種情況下,你可能想要重寫 showAction() 和 findTemplate() 方法中的一個(gè)或者都重寫。后一個(gè)方法定位了將要使用的模板。

錯(cuò)誤頁預(yù)覽對(duì)你自己建立控制器也可以使用。

處理 kernel.exception 事件

當(dāng)出現(xiàn)異常的時(shí)候,HttpKernel 類就會(huì)抓住它并且發(fā)送 kernel.exception 事件。這給你將異常以不同的方式轉(zhuǎn)換成 Response 的方法。

處理這類事件確實(shí)比以前所介紹的更加有效果,而且需要對(duì) Symfony 的內(nèi)部構(gòu)件有全面的了解。假設(shè)你的代碼出現(xiàn)特殊的異常并且對(duì)于你的應(yīng)用程序的域有特殊意義會(huì)怎樣。

kernel.exception 事件編寫你自己的監(jiān)聽器使得你可以近距離觀察異常并且依據(jù)它采取不同的行動(dòng)。這些行為可能包括記錄異常,將用戶重新定向到另一個(gè)頁面或者調(diào)用特定的錯(cuò)誤頁。

如果你的監(jiān)聽器在 GetResponseForExceptionEvent 調(diào)用 setResponse() 事件,傳播將會(huì)被禁止并且將會(huì)向客戶發(fā)出回應(yīng)。

這個(gè)方法使得你可以創(chuàng)建集中化和層次化的錯(cuò)誤處理:而不是一次又一次的在不同的控制器抓?。ㄌ幚恚┫嗤漠惓#阒恍枰粋€(gè)(或者幾個(gè))監(jiān)聽器來處理他們。

參見 ExceptionListener 類的代碼作為一個(gè)先進(jìn)的這個(gè)類型的監(jiān)聽器的真實(shí)案例。這個(gè)監(jiān)聽器處理各種各樣的你的應(yīng)用程序出現(xiàn)的安全相關(guān)的異常(如 AccessDeniedException)并且采取像將用戶重新定向到登錄頁,退出以及其它的方法。