Jump to content

Recommended Posts

Posted

Переделываю ботов на Макс.

Почти все сделал, но столкнулся со странной проблемой.

Не работает редактирование сообщений (PUT messages) и их закрепление (PUT chats/{$chat}/pin).

 

На своей стороне делаю следующее:

1. Задаю заголовок Content-Type: application/json; charset=utf-8

2. Для POST-запросов (которые работают) задаю опции CURLOPT_POST и затем CURLOPT_POSTFIELDS, в которую передаю параметры (закодированные json_encode). Для PUT-запросов вначале задаю CURLOPT_CUSTOMREQUEST (с указанием PUT), затем CURLOPT_POSTFIELDS (с параметрами, закодированными json_encode), затем добавляю заголовок Content-Length.

3. Затем выполняю запрос. Но вместо выполнения сервер Макса сообщает, что "No access token", хотя токен я передаю.

 

Если для curl включить отладку, то получается странное:

* Host platform-api.max.ru:443 was resolved.
...
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://platform-api.max.ru/messages?message_id=mid.***
* [HTTP/2] [1] [:method: PUT]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: platform-api.max.ru]
* [HTTP/2] [1] [:path: /messages?message_id=mid.***]
* [HTTP/2] [1] [accept: */*]
* [HTTP/2] [1] [content-length: 14]
* [HTTP/2] [1] [content-type: application/x-www-form-urlencoded]
> PUT /messages?message_id=mid.*** HTTP/2
Host: platform-api.max.ru
Accept: */*
Content-Length: 14
Content-Type: application/x-www-form-urlencoded

* old SSL session ID is stale, removing
< HTTP/2 401 
< server: kittenx
< date: Sat, 21 Mar 2026 11:12:49 GMT
< content-type: application/json; charset=utf-8
< content-length: 51
< cache-control: no-cache
< strict-transport-security: max-age=2592000;includeSubdomains
< 
* Connection #0 to host platform-api.max.ru left intact

Смущают две вещи. Во-первых, тип почему-то "application/x-www-form-urlencoded", хотя я задаю правильный тип:

if (isset($data))
{
	curl_setopt($this->curl, CURLOPT_POSTFIELDS, $data);
	curl_setopt($this->curl, CURLOPT_HTTPHEADER, ["Content-Length: " . strlen($data)]);
}
curl_setopt($this->curl, CURLOPT_CUSTOMREQUEST, $method);

И судя по наличию и значение заголовка Content-Length — этот код выполняется.

Во-вторых, в отладочном выводе почему-то нет тела запроса. Или в отладке он просто не выводится, или при указании CURLOPT_CUSTOMREQUEST запрос изменяется.

 

Никто с таким не сталкивался?

 

Вот отладочный вывод POST-запроса:

* Host platform-api.max.ru:443 was resolved.
...
* using HTTP/2
* [HTTP/2] [1] OPENED stream for https://platform-api.max.ru/messages?chat_id=-***
* [HTTP/2] [1] [:method: POST]
* [HTTP/2] [1] [:scheme: https]
* [HTTP/2] [1] [:authority: platform-api.max.ru]
* [HTTP/2] [1] [:path: /messages?chat_id=-***]
* [HTTP/2] [1] [accept: */*]
* [HTTP/2] [1] [authorization: ***]
* [HTTP/2] [1] [content-type: application/json; charset=utf-8]
* [HTTP/2] [1] [content-length: 438]
> POST /messages?chat_id=-*** HTTP/2
Host: platform-api.max.ru
Accept: */*
Authorization: ***
Content-Type: application/json; charset=utf-8
Content-Length: 438

* old SSL session ID is stale, removing
< HTTP/2 200 
< server: kittenx
< date: Sat, 21 Mar 2026 11:26:27 GMT
< content-type: application/json; charset=utf-8
< content-length: 1088
< vary: Accept-Encoding
< cache-control: no-cache
< strict-transport-security: max-age=2592000;includeSubdomains
< 
* Connection #0 to host platform-api.max.ru left intact

Судя по нему — тело запроса в отладку не выводится.

Но в нем, в отличии от предыдущих запросов — все заголовки передаются нормально.

 

Пробовал вначале задать тип запроса, а затем все остальное — ничего не поменялось.

Posted

В общем, похоже какой-то баг в cURL. После установки CURLOPT_CUSTOMREQUEST часть данных в запросе сбрасывается.
Продублировал установку заголовков непосредственно перед вызовом curl_exec — и запрос выполнился нормально.

  • 5 months later...
Posted

Это не похоже на баг cURL. Скорее всего, где-то раньше при настройке этого же handle задаётся CURLOPT_HTTPHEADER, и при повторной настройке он заменяется.

Важный момент: CURLOPT_HTTPHEADER не дополняет существующий список заголовков, а устанавливает его заново. Поэтому вот это:

curl_setopt($this->curl, CURLOPT_HTTPHEADER, ["Content-Length: " . strlen($data)]);

фактически выбрасывает ранее заданный Content-Type и Authorization. В результате cURL, видя CURLOPT_POSTFIELDS, сам подставляет Content-Type: application/x-www-form-urlencoded.

То, что после повторной установки всех заголовков непосредственно перед curl_exec() всё заработало, как раз хорошо это подтверждает.

Я бы сделал установку всех заголовков в одном месте, например:

curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'Authorization: ' . $token, 'Content-Type: application/json; charset=utf-8', 'Content-Length: ' . strlen($data), ]);

А Content-Length вообще можно не задавать вручную — при передаче строки через CURLOPT_POSTFIELDS cURL сам корректно сформирует его.

Отсутствие тела в CURLOPT_VERBOSE тоже само по себе ничего не доказывает: verbose-вывод cURL не обязан показывать содержимое тела запроса.

Posted
function apiRequest($method, $url, $data = null) {
    $curl = curl_init();
    
    // Базовые настройки
    curl_setopt($curl, CURLOPT_URL, $url);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_HEADER, false);
    curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
    
    $headers = [
        'Authorization: Bearer YOUR_TOKEN_HERE',
        'Content-Type: application/json; charset=utf-8'
    ];
    
    if ($method === 'POST') {
        curl_setopt($curl, CURLOPT_POST, true);
        if ($data) {
            $jsonData = json_encode($data);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonData);
            $headers[] = 'Content-Length: ' . strlen($jsonData);
        }
    } elseif ($method === 'PUT') {
        curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'PUT');
        if ($data) {
            $jsonData = json_encode($data);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $jsonData);
            $headers[] = 'Content-Length: ' . strlen($jsonData);
        }
    }
    
    curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
    
    // curl_setopt($curl, CURLOPT_VERBOSE, true);
    
    $response = curl_exec($curl);
    $info = curl_getinfo($curl);
    curl_close($curl);
    
    return [
        'response' => $response,
        'info' => $info
    ];
}

 

Пример использования:

$result = apiRequest('PUT', 'https://platform-api.max.ru/messages?message_id=mid.***', [
    'text' => 'Новый текст сообщения'
]);

 

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...