【问题标题】:Symfony request object has wrong attributes (especially `$request->header->get( 'accept' )`)Symfony 请求对象有错误的属性(尤其是`$request->header->get('accept')`)
【发布时间】:2014-11-18 07:53:33
【问题描述】:

在我的控制器函数中,我需要根据接受的内容类型和请求的发出方式返回不同的回复。但由于某种原因,$request->header->get( 'accept' )$request->getRequestFormat() 总是返回 HTML(或分别为“text/html”),尽管浏览器根据 Firebug 发送了不同的内容,并且 Wireshark 也确认原始请求确实不同。

基本上我的代码是这样的:

public function someControllerAction() {
  $request = $this->getRequest();

  if( $request->isXmlHttpRequest() && $request->getRequestFormat() == 'html' ) {
    // (1) Return some HTML fragment that is used to update the DOM at client side
  } else if( $request->isXmlHttpRequest() && $request->getRequestFormat() == 'json' ) {
    // (2) Return a JSON object
  } else if( $request->getRequestFormat() == 'html' ) {
    // (3) Return a full HTML page from a TWIG template
  }

  // In all other cases, return a 406 error
}

由于某种原因,只有 case (1) 或 case (3) 被执行,因为请求的格式总是等于 HTML。我已经试过了

die( var_dump( $request->header ) )

查看 Symfony 认为的标头是什么,我注意到标头中的其他一些细微变化与 Wireshark 所说的相比。例如,一切都转换为小写。

目前我最好的猜测是,在 Symfony 核心深处的某个地方似乎发生了某种规范化,它也将 Accept-Header-Field 替换为默认的“text/html”。有趣的是,X-Requested-With-Field 并没有被规范化,而是仍然存在。

如果请求对象返回实际的 (true) 标头字段,我需要进行哪些更改?

更新:结果

die( var_dump( getallheaders() ) );

也显示了错误的标题。 Symfony 是否会操作原生 PHP 变量,或者这是否表明 Apache 在将 accept 标头传递给 PHP 处理程序之前对其进行了处理?

【问题讨论】:

    标签: symfony http-headers xmlhttprequest


    【解决方案1】:

    我终于知道问题出在哪里了。首先,正如另一个答案中已经提到的,$request->getRequestFormat() 是另一回事。 (它与占位符_format 硬连线。)但它不是$request-getContentType(),正如评论中所讨论的那样。 HTTP-Accept-Header 可以通过$request->headers->get('accept') 获得,也可以通过$request-> getAcceptableContentTypes() 以更易于使用的方式获得。但这只是解决方案的一部分,因为$request->getAcceptableContentTypes() 仍然会返回一个包含错误值的数组。

    最终的解决方案是$request不能通过getRequest()获得,而是作为控制器方法的第一个参数。正如我在Upgrade Guide to Symfony 3 中发现的那样 getRequest() 自 2.4 起已弃用。似乎getRequest() 返回的对象与通过参数注入的对象不同,并且在某些情况下,第一种方法不能可靠地保持 Accept-Header 完整。可能,人们可以称这是一个错误,但如果getRequest() 无论如何都被弃用了,我不会打扰。 (顺便说一句:为什么连官方的 Symfony 文档“The Book”和“The Cookbook”都提供了使用过时方法的示例?!)。

    无论如何,完全可行的解决方案是

    use Symfony\Component\HttpFoundation\Request;
    
    public function someControllerAction( Request $request ) {
      if( $request->isXmlHttpRequest() && in_array( 'text/html', $request->getAcceptableContentTypes() ) ) {
        // (1) Return some HTML fragment that is used to update the DOM at client side
      } else if( $request->isXmlHttpRequest() && in_array( 'application/json', $request->getAcceptableContentTypes() ) ) {
        // (2) Return a JSON object
      } else if( in_array( 'text/html', $request->getAcceptableContentTypes() ) ) {
        // (3) Return a full HTML page from a TWIG template
      }
    
      // In all other cases, return a 406 error
    }
    

    【讨论】:

      【解决方案2】:

      请注意,$request->getRequestFormat() 不会进行实际的格式检查。它只依赖于_format 请求参数(see the doc)。你应该改用$request->getContentType()

      【讨论】:

      • 我明白了,我误解了术语“请求格式”的含义。但至少$request->headers->get( 'accept') 应该可以完成这项工作。 $request->getContentType() 完全不同。内容类型说明请求正文(有效负载)的 MIME 类型。这通常用于POSTPATCHPUT 请求。接受标头说明请求期望作为回复的内容类型的内容类型。简而言之:“content-type”决定了请求自己发送什么,“accept”决定了请求期望得到什么。在同一个请求中两者可以不同。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-18
      相关资源
      最近更新 更多