【问题标题】:406 when using Guzzle but not through browser, or command line cURL or wget使用 Guzzle 但不是通过浏览器、命令行 cURL 或 wget 时出现 406
【发布时间】:2016-10-23 20:40:52
【问题描述】:

我们有一个使用 Guzzle 5 下载 Wordpress RSS 提要的 php 网络应用程序。

除了这个提要https://www.socialquant.net/blog/feed/之外一切正常

此网站的所有者确实希望我们拉取提要,而不是故意试图阻止访问。

我可以使用 wgetcurl 从本地计算机和生产网络服务器(我们最初注意到问题的地方)成功下载文件,没有特殊选项。

这在之前发生过一次,当时我们认为该问题是由 Apache 上的 mod_security 引起的,并通过添加任意 User-Agent 标头来解决。但是那一次我能够在命令行上一致地重现这个问题,这次它只是通过 Guzzle/PHP 失败了

我已将浏览器请求中的响应标头复制到问题提要和另一个正常工作的提要中。我划掉了那些相同的,剩下的是下面的

Server:Apache/2.2.22
Vary:User-Agent
X-Powered-By:PHP/5.3.29
Content-Encoding:gzip

Server:Apache
Vary:Accept-Encoding
X-Powered-By:PHP/5.5.30

这并没有提供太多洞察力。 gzip 内容编码跳出,我正在尝试使用 gzip 找到另一个工作提要来验证这一点,但这并不重要,因为 Guzzle 的默认模式是自动处理编码。我们使用相同的设置从使用 gzip 的 CDN 下载图像。

请问有人有什么想法吗?谢谢:)

编辑

使用 Guzzle 5.3.0

代码:

$client = new \GuzzleHttp\Client();

try {
    $res = $client->get( $feed, [
      'headers' => ['User-Agent' => 'Mozilla/4.0']
    ] );
} catch (\Exception $e) {

}

【问题讨论】:

  • 您能否展示 Guzzle 部分的代码以及您正在使用的 Guzzle 5 的精确版本?
  • 刚刚编辑了帖子,谢谢:)

标签: php curl rss guzzle


【解决方案1】:

恐怕我没有适当的解决方案来解决您的问题,但我可以再次使用它。

tl;dr 版本

这是 User-Agent 标头,将其更改为几乎可以使用的任何其他内容。

wget 调用失败:

wget -d --header="User-Agent: Mozilla/4.0"  https://www.socialquant.net/blog/feed/ 

但是这行得通

wget -d --header="User-Agent: SomeRandomText" https://www.socialquant.net/blog/feed/

这样,下面的 PHP 现在也可以工作了:

require 'vendor/autoload.php';

$client = new \GuzzleHttp\Client();
$feed = 'https://www.socialquant.net/blog/feed/';

try {

    $res = $client->get( 
        $feed, 
        [
            'headers' => [
                'User-Agent' => 'SomeRandomText',
            ]
        ]
    );
    echo $res->getBody();
} catch (\Exception $e) {
    echo 'Exception: ' . $e->getMessage();
} 

我的想法

正如您所指出的,我从wgetcurl 开始,这在没有设置特殊标题或选项时有效。在我的浏览器中打开它也有效。我还尝试在没有 User-Agent 设置的情况下使用 Guzzle,这也可以。

一旦我将User-Agent 设置为Mozilla/4.0 甚至Mozilla/5.0,它开始以406 Not Acceptable 失败

根据HTTP Status Code definitions,一个406意味着

请求标识的资源只能生成响应实体,其内容特征根据请求中发送的accept headers是不可接受的。

理论上,添加 AcceptAccept-Encoding 标头应该可以解决问题,但事实并非如此。不是通过 Guzzle 或 wget

然后我找到了Mozilla Developer Network definition,上面写着:

当网络服务器在执行服务器驱动的内容协商后,没有找到任何符合 用户代理 给出的标准的内容时发送此响应。

这有点指向User-Agent。这让我相信你确实是正确的 mod_security 正在做一些奇怪的事情。我确信客户端服务器上对 mod_security 或 Apache 的更新添加了一条规则,以特定方式解析 Mozilla/* 用户代理,因为发送 User-Agent: Mozilla/4.0 () 也有效。

这就是为什么我说我没有适合你的解决方案。即使客户希望您提取提要,他们(或他们的主机)仍然可以控制规则。

注意:我注意到我的 IP 在多次尝试 406 失败后被列入黑名单,之后我不得不等待一个小时才能再次访问该站点。很可能是 mod_security 规则。 mod_security 可能甚至会通过您的用户代理接收自动请求并开始使用 406 阻止或拒绝它。

【讨论】:

  • 这绝对是多诺万的绝妙回复!由于空白用户代理导致来自不同 Apache 服务器的 406,我们在几周前任意添加了 Mozilla/4.0 User-Agent 标头。
  • 看到您的命令行调试步骤,让我意识到我在使用 cURL 进行测试时不小心将“Mozilla/4.0”传递到 Accepts 标头中。对自己很生气
  • 虽然你说你还没有找到合适的解决方案,但你找到了。我们需要使用在所有情况下都有效的 User-Agent 标头。非常感谢
  • 没问题!我想我已经准备好找到正确的标题组合以允许User-Agent: Mozilla/4.0 工作,因为我看不出有任何理由不这样做。祝您好运找到适用于所有情况的用户代理!
  • 添加了一部分我的正版用户代理,两个问题提要都允许请求“Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko)”
【解决方案2】:

我也没有适合您的解决方案,因为我也遇到了同样的问题(除了我收到错误 503 并且它在 60% 的情况下都失败了)。让我知道您是否找到了解决方案。

不过,我想与您分享我最近的研究发现。我发现某些用户代理对我来说比其他的更好。这让我相信这不是多诺万所说的(至少对我来说)。

当我将 User-Agent 设置为 null 时,它 100% 的时间都有效。但是,我还没有提出任何大的请求,因为我害怕被禁止 IP,因为我知道我会提出一个大的请求。

当我对请求本身进行 var_dump 时,我看到很多包含 Guzzle 标记的数组。我在想,也许亚马逊的检测服务可以看出我在欺骗标题?我不知道。

希望你想通了。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-05-25
    • 2021-09-30
    • 2017-05-07
    • 2020-08-16
    • 1970-01-01
    • 2019-10-28
    • 1970-01-01
    • 2011-12-10
    相关资源
    最近更新 更多