【问题标题】:Does $_SERVER['HTTP_X_REQUESTED_WITH'] exist in PHP or not?$_SERVER['HTTP_X_REQUESTED_WITH'] 是否存在于 PHP 中?
【发布时间】:2011-02-04 11:23:23
【问题描述】:

在整个互联网上,甚至包括在 Stack Overflow 上,人们都说检查请求是否为 AJAX 的好方法是执行以下操作:

if (strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' ) {...}

但是,我在official PHP documentation 中没有看到$_SERVER['HTTP_X_REQUESTED_WITH']

当我尝试执行以下操作时:

echo $_SERVER['HTTP_X_REQUESTED_WITH'];

什么都没有输出。

我做错了吗?因为我真的很希望能够使用$_SERVER['HTTP_X_REQUESTED_WITH'](如果可用)。

【问题讨论】:

    标签: php ajax http-headers


    【解决方案1】:

    $_SERVER 中的变量实际上并不是 PHP 的一部分,这就是您在 PHP 文档中找不到它们的原因。它们由 Web 服务器准备,然后将它们传递给脚本语言。

    据我所知,X-Requested-With 是由大多数主要框架的 Ajax 函数发送的,但不是全部(例如,Dojo 仅在两年前添加它:#5801)。因此,考虑到@bobince' cmets,可以肯定地说,确定请求是否为 AJAX 请求通常不是 100% 可靠的方法。

    唯一 100% 安全的方法是随请求一起发送预定义的标志(例如 GET 变量),并让接收页面检查该标志的存在。

    【讨论】:

    • 我也不认为这是一种可靠的方法。防火墙/代理工具可能会与它配合使用,如果您不将此标头与响应中的Vary: X-Requested-With 结合使用,您可能会向代理用户返回错误的响应......这反过来又会破坏 IE 中的缓存。很多人确实使用X-Requested-With,但我认为这是一个糟糕的主意。最好在查询参数中传递一个标志来表示您需要 XMLHttp 样式(或 JSON)响应。
    • @bobince 真的有可能防火墙会搞砸它吗?我正在构建一个 web 应用程序,它将主要从一个位置使用,偶尔远程使用。能够从请求类型中抽象出来真是太好了,这样我的控制器就可以返回整个页面或 html sn-p,具体取决于它是否是 ajax 请求......
    • @rgvcorley:典型的现代代理不会随意删除标头(尽管移动网络使用了一些令人讨厌的破旧的标头)。但是Vary 的问题 会困扰你,如果你除了nocache 回复之外还有其他问题。这不值得麻烦,因为头球的美观度只有很小的改善;使用一个简单的参数。
    • 感谢您的回复 - 是的,您是对的。我想,对于 GET 变量的那一点额外努力,您会因为知道它可以保证工作而受益!
    • Dojo 不是一个框架!!这是一个图书馆。 jQuery 也是一个。不幸的是,“框架”这个词演变成了一个经常被不当使用的流行词。
    【解决方案2】:

    不要忘记,您可以像这样使用 cURL 轻松欺骗任何标头

    curl_setopt($ch,CURLOPT_HTTPHEADER,array("X-Requested-With : XMLHttpRequest"));
    

    【讨论】:

    • 这里为什么使用数组而不是字符串?
    【解决方案3】:

    $_SERVERHTTP_ 开头的键是从 HTTP 请求标头生成的。在这种情况下,X-Requested-With 标头。

    【讨论】:

    • 那么所有的浏览器都设置了这个头吗?另外,如果是 AJAX 调用,这个标头是如何设置的?
    • XHR 可以在请求中发送任意标头。
    • @Hank AJAX 调用有什么问题?你认为它使用的不是HTTP请求吗?那是哪一个?
    • 我试图阻止人们直接访问我的网络服务但允许 XHR
    • @Hank 将 XHR 与“正常”请求区分开来,作为一种安全措施,从根本上来说是毫无用处的,因为每个人都可以毫无问题地模拟 XHRequest。您需要使用可靠的身份验证措施(或您的主应用程序已有的任何其他措施)来保护您的 Ajax 脚本。
    【解决方案4】:

    此标头是所有 AJAX 库的标准化进程。

    它不会记录在 php 文档本身中,而是记录在设置此标头的不同 AJAX 库中。通用库确实发送了这个头文件:jQuery、Mojo、Prototype、...

    通常这些库将使用

    设置标题
    xhrobj.setRequestHeader("X-Requested-With", "XMLHttpRequest");
    

    【讨论】:

      【解决方案5】:

      这是一个带有示例用法的快速函数:

      function isXmlHttpRequest()
      {
          $header = isset($_SERVER['HTTP_X_REQUESTED_WITH']) ? $_SERVER['HTTP_X_REQUESTED_WITH'] : null;
          return ($header === 'XMLHttpRequest');
      }
      
      // example - checking our active call
      if(!isXmlHttpRequest())
      {
          echo 'Not an ajax request';
      }
      else
      {
          echo 'is an ajax request';
      }
      

      【讨论】:

      • 这并不能回答任何问题。 OP询问的是这样的代码sn-ps。他/她想知道为什么这行得通,即这个$_SERVER['HTTP_X_REQUESTED_WITH'] 来自哪里,它在哪里设置,以及我们是否/为什么我们可以真正依赖它。
      • 尽管我同意 oscullic,但我还是在这里寻找错误的原因。这似乎已经解决了。
      【解决方案6】:
      echo $_SERVER['HTTP_X_REQUESTED_WITH'];
      

      您对这样的代码有何期望?假设您直接从浏览器运行它,而不是使用 AJAX 请求。那么,这个header是怎么设置的呢?

      生命、宇宙和万物的终极问题的答案 - HTTP 嗅探器!给自己一个,忘记打印 $_SERVER 变量。

      Firebug 有一个,或者您可能想要使用 Fiddler HTTP 代理或 LiveHTTPHeaders Mozilla 插件。我很无聊做链接,但很容易用谷歌搜索。

      因此,使用 HTTP 嗅探器,您可以确定任何 HTTP 标头。

      请注意,您不能使用 XHR 阻止任何“直接访问”,因为对您服务器的每个 HTTP 请求都已经是“直接”的。

      【讨论】:

      • 浏览器和 XHR 都没有输出
      【解决方案7】:

      你必须在你的ajax请求对象中专门设置它(也就是说,如果你没有使用像jQuery这样的框架),而是核心Javascript;像这样:

      xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
      

      xhr 是您的请求对象。

      然后,PHP 现在将接收并将其设置在全局变量 $_SERVER 中,如下所示:

      $_SERVER['HTTP_X_REQUESTED_WITH']
      

      否则 $_SERVER['HTTP_X_REQUESTED_WITH'] 将始终为空。

      注意:在您的 javascript 中,请确保在请求打开后设置标头。我的意思是在xhr.open() 方法之后。

      【讨论】:

        【解决方案8】:

        您也可以归咎于一些浏览器错误 - 请参阅此问题及其针对 Firefox 的解决方案

        Firefox does not preserve custom headers during Ajax request redirect: an ASP.NET MVC solution

        IE 也有caching issue,比检测请求方法更严重。

        您无论如何都需要添加缓存破坏器以避免缓存,所以为什么不使用另一个标志来指定 ajax 调用 - 或者更好的是您可以使用不同的 URL,例如 http://ajax.mysite.com/endpoint/sevice?params

        【讨论】:

          【解决方案9】:

          我同意佩卡。前端和后端之间没有可靠的本地方法可以自动检测客户端是否真的使用 AJAX 调用端点。

          为了我自己的使用,我有几个主要的方法来检查客户端是否正在请求我的端点之一:

          1. 当我不在跨域上下文中时,我可以使用 HTTP_X_REQUESTED_WITH。

          2. 我没有检查“X-requested-with”,而是检查 $_SERVER['HTTP_ORIGIN'](从 AJAX 请求发送),目的是处理跨域权限。大多数时候,我检查请求是否为 AJAX 请求的主要原因尤其是因为跨域权限,使用以下 PHP 代码: header('Access-Control-Allow-Origin: '.$_SERVER[' HTTP_ORIGIN']); // 如果这个“HTTP_ORIGIN”在我的白名单中

          3. 我的 API 期望客户端在少数情况下将数据类型(JSON、HTML 等)显式转换为 GET 或 POST 变量。例如,我检查 $_REQUEST['ajax'] 是否不为空或不等于预期值。

          【讨论】:

            【解决方案10】:

            确保 HTTP 请求是否真正通过 AJAX 发送的最佳解决方案是使用 SESSION 检查,您在 get 参数中发送 session_id 并检查此会话是否允许!

            【讨论】:

              【解决方案11】:
              $headers = apache_request_headers();
              $is_ajax = (isset($headers['X-Requested-With']) && $headers['X-Requested-With'] == 'XMLHttpRequest');
              

              【讨论】:

              • 这似乎没有解决实际问题。
              猜你喜欢
              • 2010-11-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-05-14
              相关资源
              最近更新 更多