【问题标题】:HTTP requests with file_get_contents, getting the response code带有 file_get_contents 的 HTTP 请求,获取响应代码
【发布时间】:2013-03-15 05:57:20
【问题描述】:

我正在尝试使用 file_get_contentsstream_context_create 来发出 POST 请求。到目前为止我的代码:

    $options = array('http' => array(
        'method'  => 'POST',
        'content' => $data,
        'header'  => 
            "Content-Type: text/plain\r\n" .
            "Content-Length: " . strlen($data) . "\r\n"
    ));
    $context  = stream_context_create($options);
    $response = file_get_contents($url, false, $context);

它工作正常,但是,当发生 HTTP 错误时,它会发出警告:

file_get_contents(...): failed to open stream: HTTP request failed! HTTP/1.0 400 Bad Request

并返回 false。有没有办法:

  • 抑制警告(我计划在失败时抛出我自己的异常)
  • 从流中获取错误信息(至少是响应码)

【问题讨论】:

    标签: php file http stream


    【解决方案1】:

    http://php.net/manual/en/reserved.variables.httpresponseheader.php

    file_get_contents("http://example.com", false, stream_context_create(['http' => ['ignore_errors' => true]]));
    var_dump($http_response_header);
    

    【讨论】:

    • 对于那些想知道的人,第一个问题的答案是将'ignore_errors' => TRUE添加到$options
    • @georg 也可以将@放在行首。
    【解决方案2】:

    我带着不同的问题进入这个页面,所以发布我的答案。我的问题是我只是试图抑制警告通知并为用户显示自定义警告消息,所以这个简单而明显的修复帮助了我:

    // Suppress the warning messages
    error_reporting(0);
    
    $contents = file_get_contents($url);
    if ($contents === false) {
      print 'My warning message';
    }
    

    如果需要,之后返回错误报告:

    // Enable warning messages again
    error_reporting(-1);
    

    【讨论】:

      【解决方案3】:

      没有一个答案(包括被 OP 接受的那个)实际上满足这两个要求:

      • 抑制警告(我打算在失败的情况下抛出我自己的异常)
      • 从流中获取错误信息(至少是响应码)

      这是我的看法:

      function fetch(string $method, string $url, string $body, array $headers = []) {
          $context = stream_context_create([
              "http" => [
                  // http://docs.php.net/manual/en/context.http.php
                  "method"        => $method,
                  "header"        => implode("\r\n", $headers),
                  "content"       => $body,
                  "ignore_errors" => true,
              ],
          ]);
      
          $response = file_get_contents($url, false, $context);
      
          /**
           * @var array $http_response_header materializes out of thin air
           */
      
          $status_line = $http_response_header[0];
      
          preg_match('{HTTP\/\S*\s(\d{3})}', $status_line, $match);
      
          $status = $match[1];
      
          if ($status !== "200") {
              throw new RuntimeException("unexpected response status: {$status_line}\n" . $response);
          }
      
          return $response;
      }
      

      这将引发非200 响应,但您可以从那里轻松工作,例如添加一个简单的 Response 类和 return new Response((int) $status, $response); 如果它更适合您的用例。

      例如,对 API 端点执行 JSON POST

      $response = fetch(
          "POST",
          "http://example.com/",
          json_encode([
              "foo" => "bar",
          ]),
          [
              "Content-Type: application/json",
              "X-API-Key: 123456789",
          ]
      );
      

      注意 "ignore_errors" => truehttp 上下文映射中的使用 - 这将防止函数针对非 2xx 状态代码抛出错误。

      对于大多数用例来说,这很可能是“正确”的错误抑制量 - 我不建议使用 @ 错误抑制运算符,因为这也会抑制错误,例如简单地传递错误的参数,这可能会无意中隐藏调用代码中的错误。

      【讨论】:

      • 太好了!但我想知道:难道没有一种不那么棘手的方法可以直接将状态码作为整数值获取吗?
      • @at54321 不是 file_get_contents,这就是它的设计方式(回到 PHP 的深沉黑暗时代),但在我自己的客户端中,我最终改用了 fopen,这避免了这种奇怪, 神奇的 API - 你可以看到 here 怎么做。
      • Documentation for $http_response_header,它确实在调用 file_get_contents() 后实现了自己。
      【解决方案4】:

      @file_get_contentsignore_errors = true 不一样: 第一个不返回任何东西; 第二个抑制错误消息,但返回服务器响应(例如 400 Bad request)。

      我使用这样的函数:

      $result = file_get_contents(
        $url_of_API, 
        false, 
        stream_context_create([
          'http' => [
            'content' => json_encode(['value1' => $value1, 'value2' => $value2]), 
            'header' => 'Authorization: Basic XXXXXXXXXXXXXXX', 
            'ignore_errors' => 1, 
            'method' => 'POST', 
            'timeout' => 10
          ]
        ])
      );
      
      return json_decode($result)->status;
      

      它返回 200(正常)或 400(错误请求)。

      它工作得很好,而且比 cURL 更容易。

      【讨论】:

      • 这如何解决这个问题?能否解释一下如何获取响应码?
      • @Nico 你觉得我的解决方案怎么样?
      • 它仍然很糟糕,因为您不解析 JSON 结果并读取名为 status 的随机字段 - 它与 API 调用的 HTTP 状态代码没有连接
      • 很明显,我连接的 RESTful API 返回一个 JSON 响应,并且我需要知道的内容(200 或 400)包含在“状态”字段中。这就是我所需要的,这就是我所得到的。如果您需要知道 HTTP 状态码,只需这样做:return $http_response_header[0];但请注意,它不适用于 @file_get_contents。
      • 这如何回答最初的问题?为什么您认为$http_response_header[0],一个高度赞成的答案,不适用于file_get_contents
      【解决方案5】:

      在接受的响应中添加几行以获取 http 代码

      function getHttpCode($http_response_header)
      {
          if(is_array($http_response_header))
          {
              $parts=explode(' ',$http_response_header[0]);
              if(count($parts)>1) //HTTP/1.0 <code> <text>
                  return intval($parts[1]); //Get code
          }
          return 0;
      }
      
      @file_get_contents("http://example.com");
      $code=getHttpCode($http_response_header);
      

      要隐藏错误输出,两个cmets都可以,ignore_errors = true or @(我更喜欢@)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-05-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多