【问题标题】:Is it possible to abort a HTTP request depending on the `Content-Type` when using Perl's LWP?使用 Perl 的 LWP 时是否可以根据“Content-Type”中止 HTTP 请求?
【发布时间】:2012-07-28 06:30:17
【问题描述】:

我希望我的脚本仅下载文本/html 内容,而不是下载可能需要更多时间的二进制或图像。我知道max_size 参数,但我想对Content-Type 标头添加检查。这可行吗?

【问题讨论】:

    标签: perl http lwp


    【解决方案1】:

    正如其他人指出的那样,您可以在 GET 请求之前执行 HEAD 请求。你应该这样做是为了对服务器有礼貌,因为实际上你很容易中止连接,但对于 Web 服务器来说,中止发送一堆数据并在其端做一堆工作并不一定容易.

    有一些不同的方法可以做到这一点,具体取决于您想要的复杂程度。

    1. 您可以在请求中发送Accept 标头,其中仅列出text/html。如果您说您不接受文件的任何内容,那么一个实施良好的 HTTP 服务器将返回 406 Not Acceptable 状态。当然,无论如何,他们可能会将其发送给您。您也可以通过 HEAD 请求执行此操作。

    2. 当使用LWP::UserAgent 的最新版本时,您可以使用处理程序子例程来中止请求头之后和内容正文之前的其余部分。

      use LWP::UserAgent;
      use Try::Tiny; 
      
      my $ua = LWP::UserAgent->new;
      $ua->add_handler( response_header => sub {
          my($response, $ua, $h) = @_;
      
          die "Not HTML" unless $response->content_type eq 'text/html';
      });
      
      my $url = "http://example.com/foo";
      
      my $html;
      my $head_response = $ua->head($url, Accept => "text/html");
      if ($head_response->is_success) {
          my $get_response = $ua->get($url, Accept => "text/html");
          if ($get_response->is_success) {
              $html = $get_response->content;
          }
      } 
      

    有关处理程序的详细信息,请参阅 LWP::UserAgent 文档的 Handlers 部分。

    我没有捕捉到抛出的异常,也没有确保在这里仔细处理 406 响应。我把它留给读者作为练习。

    【讨论】:

    • 我相信某些服务器也可能会通过HEAD 请求向您发送文件的内容。您可能还需要检查HEAD 请求上的405 Method Not Allowed 响应,看看如果HEAD 响应失败,您是否可以提交GET 请求。
    • HEAD 不可靠,在我看来,任何“正确”处理 HEAD 请求的东西也将“正确”处理 Accept 标头。我会跳过 HEAD 请求并仅使用其他两种机制(Accept 和回调)。
    • add_handler() 完全符合我的要求。谢谢!
    【解决方案2】:

    您可以使用 HEAD 请求来查询 URI 的标头信息。如果服务器响应 head,您将获得 GET 将返回的所有内容,除了那个讨厌的主体。

    然后您可以根据 MIME 类型决定做什么。

    否则,您必须在请求文件之前依赖文件的扩展名。

    【讨论】:

    • 这确实可行,但有点不理想,因为它在名义情况下使请求数量翻了一番。我得到的二进制链接很少,所以我宁愿中止这些链接,而不是为每个链接添加测试。
    • 那么为什么不能在发出 GET 之前从文件扩展名中确定文件类型呢?
    • 好吧...我有一些没有单个扩展名的情况。尤其是发送二进制数据的 cgi 脚本……所以这不是很可靠。
    • 你无法从标签中看出 URI 的来源?
    • 什么标签?我正在做的是一个机器人,它检查它遇到的网页内容。我无法控制它可能进入什么类型的链接。
    【解决方案3】:

    如果您使用LWP 的最小LWP::Simple 子类,则head 函数将内容类型作为列表的第一个元素返回。

    所以你可以写

    use strict;
    use warnings;
    
    use LWP::Simple;
    
    for my $url ('http://www.bbc.co.uk') {
      my ($ctype) = head $url;
      my $content = get $url if $ctype eq 'text/html';
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-11-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-04
      • 1970-01-01
      • 1970-01-01
      • 2016-04-11
      相关资源
      最近更新 更多