【问题标题】:FOSRestBundle setup for return JSON but still asking for Twig templateFOSRestBundle 设置返回 JSON 但仍要求 Twig 模板
【发布时间】:2015-07-18 19:09:43
【问题描述】:

我已将 FOSRestBundle 配置如下:

#FOSRestBundle
fos_rest:
    param_fetcher_listener: true
    body_listener: true
    format_listener:
        rules:
            - { path: ^/, priorities: [ json, html ], fallback_format: ~, prefer_extension: true }
        media_type:
            version_regex: '/(v|version)=(?P<version>[0-9\.]+)/'

    body_converter:
        enabled: true
        validate: true

    view:
        mime_types:
            json: ['application/json', 'application/json;version=1.0', 'application/json;version=1.1']
        view_response_listener: 'force'
        formats:
            xml:  false
            json: true
        templating_formats:
            html: true

    exception:
        codes:
            'Symfony\Component\Routing\Exception\ResourceNotFoundException': 404
            'Doctrine\ORM\OptimisticLockException': HTTP_CONFLICT
        messages:
            'Symfony\Component\Routing\Exception\ResourceNotFoundException': true
    allowed_methods_listener: true
    access_denied_listener:
        json: true

我在控制器上有这个:

namespace PDI\PDOneBundle\Controller\Rest;

use FOS\RestBundle\Controller\FOSRestController;
use Nelmio\ApiDocBundle\Annotation\ApiDoc;
use FOS\RestBundle\Controller\Annotations\QueryParam;
use FOS\RestBundle\Controller\Annotations\Get;

class RepresentativeRestController extends FOSRestController
{
    /**
     * Get all representatives.
     *
     * @return array
     *
     * @ApiDoc(
     *   resource = true,
     *       https = true,
     *   description = "Get all representatives.",
     *   statusCodes = {
     *      200 = "Returned when successful",
     *      400 = "Returned when errors"
     *   }
     * )
     * @Get("/api/v1/reps")
     */
    public function getRepsAction()
    {
        $em = $this->getDoctrine()->getManager();
        $entities = $em->getRepository('PDOneBundle:Representative')->findAll();

        if(!$entities)
        {
            return $this->view(null, 400);
        }

        return $this->view($entities, 200);
    }
}

但是当我尝试以下 URL app_dev.php/api/v1/reps 时,我收到了这个错误:

找不到模板“”。 500内部服务器错误 - InvalidArgumentException 3 链接异常:Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException »

我希望 API 返回格式正确的 JSON,如下例所示:

{
   "id":"30000001",
   "veeva_rep_id":"0055648764067SwzAAE",
   "display_name":"John Know",
   "avatar_url":"http://freelanceme.net/Images/default%20profile%20picture.png",
   "rep_type":"VEEVA",
   "username":"john@mail.com",
   "first":"John",
   "last":"Know",
   "title":"Sales Representative",
   "phone":"800-555-1212",
   "email":"john@mail.com",
   "territory_id":"200454001",
   "inactive":"no",
   "total_contacts":"6",
   "total_shares":"0",
   "totalViews":"0",
   "lastLoginAt":"2015-05-05 15:45:57",
   "lastVeevaSyncAt":"2015-05-05 15:45:57",
   "createdAt":"2015-05-05 15:45:57",
   "updatedAt":"2015-05-05 15:45:57"
}

FOSRestBundle 是否配置为返回 JSON?为什么还要求 Twig 模板?我该如何解决这个问题?

第一次测试:

正如@Jeet 建议我的那样,我尝试过使用 Postman(与他告诉我的扩展名相同)并且在将标题 Content-Type 设置为 application/json 后,错误变成了这个

格式错误的 JSON

所以,FOSRestBundle 没有按照应有的方式设置标头,并且控制器没有返回有效的 JSON,我该如何解决这些问题?

第二次测试:

按照 @Jeet 的建议,我运行了这个测试:

/**
 * Get all representatives.
 *
 * @return array
 *
 * @ApiDoc(
 *   resource = true,
 *       https = true,
 *   description = "Get all representatives.",
 *   statusCodes = {
 *      200 = "Returned when successful",
 *      400 = "Returned when errors"
 *   }
 * )
 * @Get("/api/v1/reps")
 * @View()
 */
public function getRepsAction()
{
    $em = $this->getDoctrine()->getManager();
    $entities = $em->getRepository('PDOneBundle:Representative')->findAll();

    $temp = array("1", "2", "3");

    $view = $this->view($temp, Codes::HTTP_OK);
    return $this->handleView($view);
}

还是同样的问题:

找不到模板“”。 500内部服务器错误 - InvalidArgumentException 3 链接异常:Twig_Error_Loader » InvalidArgumentException » InvalidArgumentException »

这里还有什么问题?我在配置时遗漏了什么吗?

我一开始忘了添加app/config/routing.ymlsrc/PDI/PDOneBundle/Resources/config/routing.yml,所以他们就在这里,也许这是拼图中缺少的部分,让您更好地了解问题出在哪里:

#app/config/routing.yml
#PDOne
pdone:
    resource: "@PDOneBundle/Resources/config/routing.yml"

template:
    resource: "@TemplateBundle/Resources/config/routing.yml"

#FOSUserBundle
fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"
    prefix: /

#NelmioApiDocBundle:
NelmioApiDocBundle:
    resource: "@NelmioApiDocBundle/Resources/config/routing.yml"
    prefix:   /api/doc

#SonataAdmin
admin:
    resource: '@SonataAdminBundle/Resources/config/routing/sonata_admin.xml'
    prefix: /admin

_sonata_admin:
    resource: .
    type: sonata_admin
    prefix: /admin

#src/PDI/PDOneBundle/Resources/config/routing.yml
pdone:
    resource: "@PDOneBundle/Controller/"
    type:     annotation
    prefix:   /

第三次测试:

来自客户端的请求肯定有问题,如果我使用像Postman 这样的工具并设置正确的标头,我会得到我想要的实体,见下图:

我找不到问题出在哪里,所以我在这里非常需要有人的帮助,因为我已经没有想法了

【问题讨论】:

  • 您是否将 'Content-Type' 设置为 'application/json' ?
  • @Jeet 我应该在哪里做?是不是像您在 OP 上看到的那样处于 FOSRes 的配置?
  • 在 Google Chrome 的 Advanced Rest Client 应用程序(应用程序扩展)中尝试 app_dev.php/api/v1/reps,您将有一个选择。
  • @Jeet 看到 OP,我已经编辑添加了一些信息
  • FOSRestBundle 负责为其发送给客户端的响应设置标头。但其客户端(移动应用程序、REST 客户端扩展)有责任在将其发送到服务器时设置正确的标头值。 FOSRestBundle 可以做出相应的回应。 ;)

标签: php json symfony fosrestbundle symfony-2.6


【解决方案1】:

正如大家所建议的那样:只有 Accept 标头或扩展名才能为您提供 JSON。似乎您已经使用 Accept 标头进行了排序。

为了使用扩展,你必须告诉你想如何在 Symfony 中设置格式。

这段代码应该会给你一个你想要的输出:

namespace RestTestBundle\Controller;

use FOS\RestBundle\Controller\Annotations\View;

use FOS\RestBundle\Controller\Annotations\Get;

class YourController
{
    /**
     * @Get("/api/v1/reps.{_format}", defaults={"_format"="json"})
     * @View()
     */
    public function indexAction()
    {
        return array(
            'status' => 'ok',
            'companies' => array(
                array('id' => 5),
                array('id' => 7),
            ),
        );
    }
}

Edit1:如果您不想使用 View 类,而是使用纯数组:不要忘记禁止 SensioExtraBundle 的视图处理

sensio_framework_extra:
    view:    { annotations: false }

Edit2:如果你不使用 HTML 格式,只想有一个 json 输出,你可以使用这样的配置:

fos_rest:
    # ....
    format_listener:
        rules:
            - { path: ^/, priorities: [ json ], fallback_format: json, prefer_extension: true }
    # ....

解释您看到“未找到视图”错误的原因:

TL;DR:您的浏览器会发送一个 Accept 标头,告诉 FOSRestBundle 输出一个“html”变体。

背景:此捆绑包主要与 Accept 标头一起使用,最好使用所有可能的输出格式:html(您可以使用您提供的表单、对象列表、对象详细信息通过这种方式轻松测试您的 REST API )、json、xml。有时甚至是图像 mime 类型,例如 image/jpeg、image/png 作为默认值或 json/xml 作为变体(您可以使用 base64 图像表示)。

说明:如果您打开浏览器的“网络”选项卡并查看它发送的标头,您会注意到类似:text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 的意思是“按此顺序使用”:

  1. 文本/html
  2. 应用程序/xhtml+xml
  3. application/xml 优先级为 0.9,根据您的配置禁止使用
  4. */* 优先级 0.8 表示任何格式

如果您仔细观察,您会发现根据您的配置,text/html 是您的配置具有的变体之一('html')和 */* em> 是另一个('json'),但是 text/html 的优先级是 1,而 */* 的优先级是 0.8,所以 text /html 匹配,FOSRestBundle 尝试查找 HTML 表示并失败。

PS:如果您多次发布问题 - 请确保注意每个帖子中的所有回复。

【讨论】:

    【解决方案2】:

    你可以通过两种方式给予回应

    return View::create($entities, Codes::HTTP_OK);
    

    $view = $this->view($entities, Codes::HTTP_OK);    
    return $this->handleView($view)
    

    【讨论】:

    • 这种方式有效,但只能通过 Postman Chrome 扩展程序通过为Content-Type 设置正确的标题,如果我从浏览器尝试我遇到了与模板相同的问题,这让我问:为什么?配置问题出在哪里,为什么标头设置不正确?如果没有$entities,我也想返回某种NotFoundException,你能告诉我如何在你的代码上实现吗?
    【解决方案3】:

    你可以简单地使用

                $view = new View($form);
                $view->setFormat('json');
                return $this->handleView($view);
    

    【讨论】:

      【解决方案4】:

      FosRestBundle 利用 Accept Header。这意味着它会根据您的请求返回响应。通过访问“app_dev.php/api/v1/reps”路由,你隐式请求了一个html格式,所以它会尝试提供一个模板。

      app_dev.php/api/v1/reps.json 是否返回您需要的内容?

      您还应该测试 app_dev.php/api/v1/reps.xml 并期待 xml 输出

      【讨论】:

      • 这三个都不适合我,当我输入 .html.json.xml 时,我收到 404 路由错误,我在配置中找不到我丢失的内容或在控制器端
      • 您的回复有解决方案,但它隐含在内容中。您应该专门描述使用 Chrome/Firefox RestClient 扩展等某些客户端进行测试时必须设置正确的标头:Accept:application/json
      猜你喜欢
      • 2015-05-30
      • 1970-01-01
      • 2012-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多