我正在尝试让我的自定义json错误模板由Symfony返回,但它不断返回HTML版本.使用rest客户端我已将Accept和Content-Type设置为"application/json",但只返回error404.html.twig的内容,而不是error404.json.twig文件.
目前我正在通过一个完全无效的URL(即没有路由)对此进行测试,但是一旦我开始工作,我也会将其用于有效的URL,这些URL不会导致资源,并且内部代码会抛出HttpNotFoundException
在请求中设置标头实际上不会对返回的错误模板产生任何影响,尽管看起来这可能是逻辑路径。生成的错误模板基于请求格式,该格式可以在参数中设置_format,也可以在对象本身上手动设置Request。这篇文章中有一个解决方案,但如果您收到 404 错误,则无法准确设置参数_format或$request->setRequestFormat('json')从不存在路由的控制器进行调用。
Symfony 有非常好的文档说明如何自定义错误页面,包括您可能想要采用的路径,该路径会覆盖默认值ExceptionController。本质上,您将重写showAction()orfindTemplate()方法,该方法将采用Acceptheader 并检查application/json. 您还可以检查Content-Type标头作为附加要求。所以这是你的听众的声明:
# app/config/services.yml
services:
app.exception_controller:
class: AppBundle\Controller\CustomExceptionController
arguments: ['@twig', '%kernel.debug%']
Run Code Online (Sandbox Code Playgroud)
然后设置Twig参数:
# app/config/config.yml
twig:
exception_controller: app.exception_controller:showAction
Run Code Online (Sandbox Code Playgroud)
现在定义您的类并覆盖您需要的相关部分。第一个示例showAction()通过检查Accept标头然后修改Request格式来覆盖:
namespace AppBundle\Controller;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController;
class CustomExceptionController extends ExceptionController
{
/*
* {@inheritDoc}
*/
public function showAction(Request $request, FlattenException $exception, DebugLoggerInterface $logger = null)
{
if (in_array('application/json', $request->getAcceptableContentTypes())) {
$request->setRequestFormat('json');
}
parent::showAction($request, $exception, $logger);
}
}
Run Code Online (Sandbox Code Playgroud)
Symfony 表示该findTemplate()方法是定位要使用的模板的方法,因此您可以将代码放在那里。下面是一个覆盖该函数的示例,Content-Type如果您需要满足这两个条件,则需要对标头进行额外检查:
namespace AppBundle\Controller;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController;
class CustomExceptionController extends ExceptionController
{
/*
* {@inheritDoc}
*/
protected function findTemplate(Request $request, $format, $code, $showException)
{
if (in_array('application/json', $request->getAcceptableContentTypes()) &&
0 === strpos($request->headers->get('Content-Type'), 'application/json')
) {
$format = 'json';
}
parent::findTemplate($request, $format, $code, $showException);
}
}
Run Code Online (Sandbox Code Playgroud)
当然,您也可以通过使用kernel.exception事件来自己创建异常侦听器以进行进一步的控制。
如果您使用 FOSRestBundle,它会尝试使用标头和格式优先级配置通过侦听器为您确定请求格式。Request Accept如果您使用此捆绑包,您可能能够避免自定义编码并仅依赖它。