PHP cURL 发出相同的请求两次

-2 php post curl http

我正在发出 POST 请求以https://api.mercadolibre.com/oauth/token生成有效的访问令牌。我发送带有一些附加信息的代码以接收回令牌。

我有以下请求类:

class Request {

    private function httpRequest(
        string $method,
        string $url,
        array $headers,
        array $data=array()
    ) {
        $curl = curl_init();

        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers
        ));

        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($curl, CURLOPT_HEADER, 0);

        if ($method != "GET" && $data) {
            curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
        }

        if (!$response = curl_exec($curl)) {
            trigger_error(curl_error($curl));
        }

        $response = curl_exec($curl);

        if (curl_errno($curl)) {
            $error = curl_errno($curl)." - ".curl_error($curl);
        }

        curl_close($curl);
        
        if (isset($error)) {
            return $error;
        }

        return $response;
    }

    public function get(
        string $url,
        array $headers,
        array $data=array()
    ) {
        if ($data) {
            $url = Utils::urlParams($url, $data);
        }

        return $this->httpRequest($method = "GET", $url, $headers);
    }

    public function post(
        string $url,
        array $headers,
        array $data=array()
    ) {
        return $this->httpRequest($method = "POST", $url, $headers, $data);
    }

    public function put(
        string $url,
        array $headers,
        array $data
    ) {
        return $this->httpRequest($method = "PUT", $url, $headers, $data);
    }
}
Run Code Online (Sandbox Code Playgroud)

当我需要请求访问令牌时,我使用以下方法访问 ML 类的方法$response = $ml->accessToken();

public function accessToken() {
        if (isset($_GET["code"])) {
            $code = $_GET["code"];

            $token_headers = Utils::defaultHeaders();

            $token_data = array(
                "grant_type" => "authorization_code",
                "client_id" => $this->client_id,
                "client_secret" => $this->client_secret,
                "code" => $code,
                "redirect_uri" => $this->redirect_uri
            );

            // var_dump($this->token_url);
            // var_dump($token_headers);
            // var_dump($token_data);
            // var_dump($code);

            $response = $this->request->post(
                $this->token_url,
                $token_headers,
                $token_data
            );

            return $response;
        }
        
        return -1;
    }
Run Code Online (Sandbox Code Playgroud)

但是,我收到以下回复:

{"cause":[],"error":"invalid_grant","error_description":"Error validating grant. Your authorization code or refresh token may be expired or it was already used","status":400}
Run Code Online (Sandbox Code Playgroud)

这根本没有意义,因为我收到了当时生成的全新代码。这只能意味着 cURL 发送了两次 POST 请求!

我尝试将httpRequest的 CURLOPT_RETURNTRANSFER 更改为 false 以查看它记录的内容,如下所示:

private function httpRequest(
        string $method,
        string $url,
        array $headers,
        array $data=array()
    ) {
        $curl = curl_init();

        curl_setopt_array($curl, array(
            CURLOPT_URL => $url,
            // CURLOPT_RETURNTRANSFER => true,      // Altered!
            CURLOPT_RETURNTRANSFER => false,        // Altered!
            CURLOPT_ENCODING => "",
            CURLOPT_MAXREDIRS => 10,
            CURLOPT_TIMEOUT => 0,
            CURLOPT_FOLLOWLOCATION => true,
            CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
            CURLOPT_CUSTOMREQUEST => $method,
            CURLOPT_HTTPHEADER => $headers
        ));

        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($curl, CURLOPT_HEADER, 0);

        if ($method != "GET" && $data) {
            curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data));
        }

        if (!$response = curl_exec($curl)) {
            trigger_error(curl_error($curl));
        }

        // $response = curl_exec($curl);         // Altered!
        curl_exec($curl);                        // Altered!

        if (curl_errno($curl)) {
            $error = curl_errno($curl)." - ".curl_error($curl);
        }

        curl_close($curl);
        
        if (isset($error)) {
            return $error;
        }

        // return $response;         // Altered!
    }
Run Code Online (Sandbox Code Playgroud)

并且准确无误!我收到以下消息(全部在同一行):

{"access_token":"APP_USR-731450979634979-062614-76a6db201965f6c18c1108cebc48fb1d-1405568857","token_type":"Bearer","expires_in":21600,"scope":"offline_access read write","user_id":1405568857,"refresh_token":"TG-6499d6c7eea12900019aba4d-1405568857"}
{"cause":[],"error":"invalid_grant","error_description":"Error validating grant. Your authorization code or refresh token may be expired or it was already used","status":400}
Run Code Online (Sandbox Code Playgroud)

这意味着我实际上收到了我需要的令牌,但是它被失败的第二个请求推翻了。

100% 确定我只执行请求方法一次。自从我尝试了各种各样的事情后,我变得非常沮丧。

我需要将 CURLOPT_RETURNTRANSFER 设置为 true,以便之后可以访问令牌来存储它,但是我收到的唯一返回是告诉我我正在使用的代码已过期(一开始还没有过期!)。

拜托,你能帮我吗?先感谢您。

Dav*_*Boy 5

你调用它两次:

if (!$response = curl_exec($curl)) {
    trigger_error(curl_error($curl));
}

$response = curl_exec($curl);
Run Code Online (Sandbox Code Playgroud)

该行中的代码if (!$response = curl_exec($curl))进行调用,将结果分配给$response,然后检查结果。如果该响应出现错误,trigger_error则调用。然后,下一行使用相同的参数重复调用curl_exec,但不关心结果。