Yêu cầu HTTP với file_get_contents, nhận mã phản hồi


87

Tôi đang cố gắng sử dụng file_get_contentscùng với stream_context_createđể thực hiện các yêu cầu ĐĂNG. Mã của tôi cho đến nay:

    $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);

Nó hoạt động tốt, tuy nhiên, khi lỗi HTTP xảy ra, nó sẽ đưa ra cảnh báo:

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

và trả về false. Có cách nào để:

  • ngăn chặn một cảnh báo (Tôi dự định đưa ra ngoại lệ của riêng mình trong trường hợp thất bại)
  • lấy thông tin lỗi (ít nhất là mã phản hồi) từ luồng

Câu trả lời:



19

Không có câu trả lời nào (kể cả câu trả lời được OP chấp nhận) thực sự đáp ứng hai yêu cầu:

  • ngăn chặn một cảnh báo (Tôi dự định đưa ra ngoại lệ của riêng mình trong trường hợp thất bại)
  • lấy thông tin lỗi (ít nhất là mã phản hồi) từ luồng

Đây là cách của tôi:

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;
}

Điều này sẽ tạo ra một 200phản hồi không , nhưng bạn có thể dễ dàng làm việc từ đó, ví dụ: thêm một Responselớp đơn giản và return new Response((int) $status, $response);nếu nó phù hợp với trường hợp sử dụng của bạn hơn.

Ví dụ: để thực hiện một JSON POSTtới một điểm cuối API:

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

Lưu ý việc sử dụng "ignore_errors" => truetrong httpbản đồ ngữ cảnh - điều này sẽ ngăn hàm tạo lỗi cho mã trạng thái không phải 2xx.

Đây rất có thể là lượng triệt lỗi "phù hợp" cho hầu hết các trường hợp sử dụng - Tôi không khuyên bạn nên sử dụng @toán tử triệt lỗi, vì điều này cũng sẽ ngăn chặn các lỗi như chỉ truyền sai đối số, điều này có thể vô tình ẩn một lỗi trong mã gọi.


5

Thêm vài dòng nữa vào câu trả lời được chấp nhận để nhận mã 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);

để ẩn kết quả đầu ra lỗi, cả hai bình luận đều ok, ignore_errors = true hoặc @ (tôi thích @ hơn)


-1

Tôi truy cập trang này với một loại vấn đề khác, vì vậy tôi đăng câu trả lời của mình. Vấn đề của tôi là tôi chỉ đang cố gắng ngăn thông báo cảnh báo và hiển thị thông báo cảnh báo tùy chỉnh cho người dùng, vì vậy, bản sửa lỗi đơn giản và rõ ràng này đã giúp tôi:

// Suppress the warning messages
error_reporting(0);

$contents = file_get_contents($url);
if ($contents === false) {
  print 'My warning message';
}

Và nếu cần, hãy quay lại báo cáo lỗi sau đó:

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

-2

@file_get_contentsignore_errors = truekhông giống nhau: đầu tiên không trả lại bất cứ điều gì; thứ hai ngăn chặn các thông báo lỗi, nhưng trả về phản hồi của máy chủ (ví dụ: 400 Yêu cầu không hợp lệ).

Tôi sử dụng một chức năng như thế này:

$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;

Nó trả về 200 (Ok) hoặc 400 (Yêu cầu không hợp lệ).

Nó hoạt động hoàn hảo và dễ dàng hơn cURL.


Và điều này giải quyết câu hỏi như thế nào? Bạn có thể giải thích cách lấy mã phản hồi không?
Nico Haase

@Nico Bạn nghĩ gì về giải pháp của tôi?
Besen

Nó vẫn là một điều tồi tệ, vì bạn không phân tích cú pháp kết quả JSON và đọc một trường ngẫu nhiên có tên status- nó không có kết nối với mã trạng thái HTTP cho lệnh gọi API
Nico Haase

Rõ ràng là RESTful API mà tôi kết nối để trả về phản hồi JSON và những gì tôi cần biết cho mục đích của mình (200 hoặc 400) được chứa trong trường "trạng thái". Đó là tất cả những gì tôi cần và đó là tất cả những gì tôi nhận được. Nếu bạn cần biết mã trạng thái HTTP, chỉ cần làm như sau: return $ http_response_header [0]; Nhưng lưu ý rằng nó không hoạt động với @file_get_contents.
Besen

Và điều này trả lời câu hỏi ban đầu như thế nào? Bạn nghĩ tại sao $http_response_header[0]câu trả lời được tán thành cao lại không phù hợp file_get_contents?
Nico Haase
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.