我正在发出 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,以便之后可以访问令牌来存储它,但是我收到的唯一返回是告诉我我正在使用的代码已过期(一开始还没有过期!)。
拜托,你能帮我吗?先感谢您。
你调用它两次:
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,但不关心结果。