POST и GET запросы без cURL
С помощью PHP мы можем отправить простой GET запрос используя функцию file_get_contents.
Пример:
$result = file_get_contents('https://phpstack.ru/');
Теперь у нас в переменной $result записан весь html код главной страницы этого сайта.
Мы совершили GET запрос, а html код — это ответ на него.
При помощи file_get_contents мы также можем отправить POST запрос.
Пример:
$postData = http_build_query(); $opts = [ 'http' => [ 'method' => 'POST', 'header' => 'Content-type: application/x-www-form-urlencoded', 'content' => $postData ] ]; $context = stream_context_create($opts); $result = file_get_contents('https://httpbin.org/anything', false, $context);
Подробнее о том, какие опции можно передавать в stream_context_create, вы можете изучить здесь: http://docs.php.net/manual/ru/context.http.php
В $result мы получили ответ на POST запрос. httpbin.org — это сторонний сервис, который вы можете использовать для отладки запросов. Он возвращает нам наш собственный запрос в формате JSON и еще некоторую информацию. Так мы можем увидеть, что мы отправляем в своих запросах.
Как видите file_get_contents — полезная функция, которая не только позволяет читать файлы на нашем сервере, но еще и отправлять запросы.
Подробнее о ней вы можете прочитать здесь: https://www.php.net/manual/ru/function.file-get-contents.php
удалить возвращаемое значение
удалить экземпляр запроса, метод запроса использует HttpMethod.DELETE
Другая статья
Недавно при использовании класса инструментов Spring RestTemplate для запроса интерфейса я обнаружил ямку в передаче параметров, то есть, когда мы инкапсулируем параметры в карту, выбирается тип карты. При использовании пост-запроса RestTemplate есть три основных способа достижения
1. Вызовите метод postForObject 2. Используйте метод postForEntity 3. Вызовите метод обмена.
Основное различие между методами postForObject и postForEntity заключается в том, что вы можете установить свойства заголовка в методе postForEntity. Если вам нужно указать значения свойств заголовка, используйте метод postForEntity. Метод обмена похож на postForEntity, но более гибкий. Exchange также может вызывать запросы на получение, размещение и удаление. Используйте эти три метода для вызова почтового запроса для передачи параметров. Карта не может быть определена как следующие два типа (за исключением случаев, когда URL-адрес использует заполнители для передачи параметров)
После тестирования я обнаружил, что параметры на этих двух картах не могут быть получены в фоновом режиме. Эта проблема беспокоила меня в течение двух дней. Наконец, когда я изменил тип карты на LinkedMultiValueMap, параметры были успешно переданы в фоновый режим.
После тестирования правильный способ передачи параметров выглядит следующим образом
Описание передачи параметра GET
Если это запрос получения, и вы хотите инкапсулировать параметры в карту для передачи, карта должна использовать HashMap, а URL-адрес должен использовать заполнители, как показано ниже:
Ссылка:
Более сложный POST запросы¶
Как правило, вы хотите отправить некоторые закодированные в форме данные —
очень похоже на HTML-форму. Для этого просто передайте словарь в аргумент
. Ваш словарь данных будет автоматически закодирован, когда будет
сделан запрос:
>>> payload = {'key1' 'value1', 'key2' 'value2'} >>> r = requests.post("https://httpbin.org/post", data=payload) >>> print(r.text) { ... "form": { "key2": "value2", "key1": "value1" }, ... }
Аргумент также может иметь несколько значений для каждого ключа. Это
можно сделать, сделав либо списком кортежей, либо словарем со списками
в качестве значений. Это особенно полезно, когда в форме есть несколько
элементов, использующих один и тот же ключ:
>>> payload_tuples = >>> r1 = requests.post('https://httpbin.org/post', data=payload_tuples) >>> payload_dict = {'key1' 'value1', 'value2']} >>> r2 = requests.post('https://httpbin.org/post', data=payload_dict) >>> print(r1.text) { ... "form": { "key1": [ "value1", "value2" }, ... } >>> r1.text == r2.text True
Бывают случаи, когда вам может потребоваться отправить данные, не
закодированные в форме. Если вы передадите вместо , эти
данные будут опубликованы напрямую.
Например, GitHub API v3 принимает данные POST/PATCH в кодировке JSON:
>>> import json >>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some' 'data'} >>> r = requests.post(url, data=json.dumps(payload))
Вместо того, чтобы кодировать самостоятельно, вы также можете передать
его напрямую, используя параметр (добавлен в версии 2.4.2), и он будет
закодирован автоматически:
>>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some' 'data'} >>> r = requests.post(url, json=payload)
Обратите внимание, что параметр игнорируется, если передан
или
Дополнительные команды для просмотра параметров Response библиотеки Requests Python
Пример скрипта Python:
# Импорт библиотеки requests import requests # Запрос GET (Отправка только URL без параметров) response = requests.get("http://api.open-notify.org/iss-pass.json?lat=40.71&lon=-74") # Вывод ответа, через пользовательскую функцию jprint print("response:\n{}\n\n".format(response)) print("response.url:\n{}\n\n".format(response.url)) #Посмотреть формат URL (с параметрами) print("response.headers:\n{}\n\n".format(response.headers)) #Header of the request print("response.status_code:\n{}\n\n".format(response.status_code)) #Получить код ответа print("response.text:\n{}\n\n".format(response.text)) #Text Output print("response.encoding:\n{}\n\n".format(response.encoding)) #Узнать, какую кодировку использует Requests print("response.content:\n{}\n\n".format(response.content)) #В бинарном виде print("response.json():\n{}\n\n".format(response.json())) #JSON Output
Результат:
response: <Response > response.url: http://api.open-notify.org/iss-pass.json?lat=40.71&lon=-74 response.headers: {'Server': 'nginx/1.10.3', 'Date': 'Tue, 07 Apr 2020 05:44:13 GMT', 'Content-Type': 'application/json', 'Content-Length': '519', 'Connection': 'keep-alive', 'Via': '1.1 vegur'} response.status_code: 200 response.text: { "message": "success", "request": { "altitude": 100, "datetime": 1586237266, "latitude": 40.71, "longitude": -74.0, "passes": 5 }, "response": } response.encoding: None response.content: b'{\n "message": "success", \n "request": {\n "altitude": 100, \n "datetime": 1586237266, \n "latitude": 40.71, \n "longitude": -74.0, \n "passes": 5\n }, \n "response": \n}\n' response.json(): {'message': 'success', 'request': {'altitude': 100, 'datetime': 1586237266, 'latitude': 40.71, 'longitude': -74.0, 'passes': 5}, 'response': }
Скачивание больших файлов с помощью cURL
Для того, чтобы скачать большой файл пригодится этот способ:
$url = 'https://example.com/big_file.zip'; // откуда скачиваем файл $path = __DIR__ . '/big_file.zip'; // куда сохраняем файл $fp = fopen($path, 'w'); $ch = curl_init($url); curl_setopt($ch, CURLOPT_FILE, $fp); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); $data = curl_exec($ch); curl_close($ch); fclose($fp);
Обратите внимание, если вы будете использовать file_get_contents для скачивания файлов, то файл сначала загружается в оперативную память, а потом сохраняется на диск. Поэтому если файл действительно большой, то скорее всего вашему серверу не хватит памяти
Также к памяти будет требователен следующий код:
$ch = curl_init('https://example.ru/big_file.zip'); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HEADER, false); $data = curl_exec($ch); curl_close($ch); file_put_contents(__DIR__ . '/big_file.zip', $data);
Здесь мы скачиваем файл при помощи cURL в оперативную память, а затем сохраняем его на диск. Не смотря на то, что этот способ не годится для скачивания больших файлов, с помощью него можно вполне сохранить простую веб страницу.
POST запросы cUrl в PHP
$array = array( 'login' => 'user', 'password' => '123' ); $ch = curl_init('https://asgeto.ru'); curl_setopt($ch, CURLOPT_POST, 1); curl_setopt($ch, CURLOPT_POSTFIELDS, $array); // Или предать массив строкой: // curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($array, '', '&')); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_HEADER, false); $html = curl_exec($ch); curl_close($ch); echo $html;
Функция file_get_contents() так же умеет отправлять POST запросы. Для этого нужно использовать заголовки:
$headers = stream_context_create(array( 'http' => array( 'method' => 'POST', 'header' => 'Content-Type: application/x-www-form-urlencoded' . PHP_EOL, 'content' => 'login=user&password=123', ), )); echo file_get_contents('https://asgeto.ru', false, $headers);
👨💻 Создаем запрос к OpenWeatherAPI с помощью curl
- Предположим, что практическое занятие раздела выполнено, возвращаемся в Postman.
- В любом запросе кликаем на кнопку под кнопкой
- В диалоговом окне “Generate Code Snippets” выбираем cURL из выпадающего списка и нажимаем на кнопку
Код Postman для запроса прогноза погоды OpenWeatherMap выглядит в формате cURL следующим образом:
Postman добавил свою информацию о хедере (обозначено -Н) Тэги добавленного заголовка можно удалить. Также можно удалить знаки “», они добавлены для читаемости текста.
Кроме того, обратите внимание, что в Windows нужно изменить одинарные кавычки на двойные, потому что одинарные кавычки не поддерживаются в терминале Windows по умолчанию. Вот запрос curl с удаленными символами -H и обратной косой чертой, а одинарные кавычки преобразованы в двойные кавычки:
Вот запрос curl с удаленными символами -H и обратной косой чертой, а одинарные кавычки преобразованы в двойные кавычки:
- Curl доступен на MacOS по умолчанию. Если на Windows curl еще не установлен, то инструкции по установке по , нужно выбрать одну из бесплатных версий с правами Администратора.
- Открываем терминал
- на OS Windows нажимаем и вводим команду , Правой кнопкой мыши вызываем меню и выбираем для вставки запроса.
- на MacOS открываем iTerm или терминал, нажимая и вводим команду Вставляем запрос в командную строку и жмем кнопку .
Ответ от OpenWeatherMap на наш запрос будет выглядеть так:
Этот запрос минимизирован. Вы можете развернуть его, например на сайте JSON pretty print или, на MacOS с установленным Python добавив в конец cURL запроса, чтобы минимизировать JSON в ответе (Для подробностей можно посмотреть ветку на Stack Overflow по этой теме).
Самостоятельно сделаем curl запрос на 5-дневный прогноз, сохраненный в Postman. И третий API запрос OpenWeatherMap? сохраненный в Postman тоже выполняем в curl
Получаем последний статус Twitter
С помощью PHP и cURL очень просто получить статус определённого пользователя. Данную информацию можно выводить в блоге.
function get_status($twitter_id, $hyperlinks = true) { $c = curl_init(); curl_setopt($c, CURLOPT_URL, "http://twitter.com/statuses/user_timeline/$twitter_id.xml?count=1"); curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); $src = curl_exec($c); curl_close($c); preg_match('/<text>(.*)<\/text>/', $src, $m); $status = htmlentities($m); if( $hyperlinks ) $status = ereg_replace("]+://]+/]", '<a href="%5C%22%5C%5C0%5C%22">\\0</a>', $status); return($status); }
Использовать функцию очень просто:
echo get_status('catswhocode');
Редиректы (перенаправления)
Guzzle будет автоматически следовать за редиректами, только если чётко не указать этого не делать. Вы можете настроить поведение перенаправления, используя опцию запроса :
- Установите значение , чтобы включить нормальные перенаправления с максимальным количеством 5 перенаправлений. Это значение по умолчанию.
- Установите в , чтобы отключить перенаправления.
- Передайте ассоциативный массив, содержащий ключ , чтобы указать максимальное количество перенаправлений, и при необходимости укажите значение ключа , чтобы указать, следует ли использовать строгие перенаправления, совместимые с RFC (что означает запросы перенаправления POST со следующими запросами тоже типа POST, тогда как в обычном режиме большинство браузеров по умолчанию перенаправляют запросы POST со следующими запросами GET)./li>
$response = $client->request('GET', 'http://github.com'); echo $response->getStatusCode(); // 200
В следующем примере показано, как можно отключить редиректы:
$response = $client->request('GET', 'http://github.com', ); echo $response->getStatusCode(); // 301
Подготовка Requests¶
Каждый раз, когда вы получаете объект из
вызова API или сеанса, атрибут фактически является использованным
. В некоторых случаях вы можете захотеть проделать
дополнительную работу с телом или заголовками (или чем-то ещё) перед отправкой
запроса. Простой рецепт для этого следующий:
from requests import Request, Session s = Session() req = Request('POST', url, data=data, headers=headers) prepped = req.prepare() # сделать что-нибудь с prepped.body prepped.body = 'No, I want exactly this as the body.' # сделать что-нибудь с prepped.headers del prepped.headers'Content-Type' resp = s.send(prepped, stream=stream, verify=verify, proxies=proxies, cert=cert, timeout=timeout ) print(resp.status_code)
Поскольку вы не делаете ничего особенного с объектом , вы готовите
его немедленно и изменяете объект . Затем вы отправляете его
с другими параметрами, которые вы бы отправили на или
.
Однако приведенный выше код теряет некоторые преимущества наличия объекта
Requests . В частности, к вашему запросу не
будет применяться состояние уровня , такое как
cookie. Чтобы получить
с этим состоянием, замените вызов на вызов , например так:
from requests import Request, Session s = Session() req = Request('GET', url, data=data, headers=headers) prepped = s.prepare_request(req) # сделать что-нибудь с prepped.body prepped.body = 'Seriously, send exactly these bytes.' # сделать что-нибудь с prepped.headers prepped.headers'Keep-Dead' = 'parrot' resp = s.send(prepped, stream=stream, verify=verify, proxies=proxies, cert=cert, timeout=timeout ) print(resp.status_code)
Когда вы используете подготовленный поток запросов, имейте в виду, что он не
принимает во внимание среду. Это может вызвать проблемы, если вы используете
переменные среды для изменения поведения requests
Например: самоподписанные
сертификаты SSL, указанные в , не будут учитываться. В
результате выдается . Вы можете обойти это
поведение, явно объединив настройки среды в свой сеанс:
Ответ (Response)
class Cake\Http\Response
Cake\Http\Response — это класс ответа по умолчанию в CakePHP. Он объединяет в себе определенный функционал для генерации HTTP ответов приложения. Cake\Http\Response также помогает при тестировании, поскольку его можно обойти/пропустить, для проверки заголовков, которые будут отправлены. Подобно Cake\Http\ServerRequest, Cake\Http\Response объединяет ряд методов, ранее относящихся к контроллеру: RequestHandlerComponent и Dispatcher. Старые методы устарели в пользу использования Cake\Http\Response.
Response предоставляет интерфейс для объединения задач, связанных с ответом, таких как:
- Отправка заголовков для перенаправления;
- Отправка content type заголовков;
- Отправка прочих заголовков;
- Отправка тела ответа.
Работа с типами контента
Cake\Http\Response::withType($contentType = null)
Вы можете управлять Content-Type в ответах приложения с помощью Cake\Http\Response::withType(). Если приложению нужно иметь дело с Content-Types, которые не встроены в Response, их можно также сопоставить с type():
Обычно необходимо отображать дополнительные Content-Type в обратном вызове beforeFilter() контроллера, для этого можно использовать функции автоматического переключения вида , при его использовании.
Отправка файлов
Cake\Http\Response::withFile($path, $options = [])
Бывают случаи, когда необходимо отправлять файлы в качестве ответов на запросы. Это можно делать, используя Cake\Http\Response::withFile():
Как показано в приведённом выше примере, необходимо в метод передать путь к файлу. CakePHP отправит соответствующий заголовок типа контента, если это известный тип файла, указанный в Cake\Http\Reponse::$_mimeTypes. Вы можете добавлять новые типы до вызова Cake\Http\Response::withFile() с помощью метода Cake\Http\Response::withType().
Также можно принудительно загрузить файл вместо отображения страницы в браузере, указав параметры:
Поддерживаемые параметры:
- name — позволяет указать альтернативное имя файла для отправки пользователю;
- download — логическое значение, указывающее, следует ли устанавливать заголовки для принудительной загрузки.
Отправка строки в виде файла
Так же, можно ответить файлом, который не существует на диске, например, pdf или ics, сгенерированным «на лету» из строки:
Обратные вызовы также могут возвращать тело в виде строки:
Настройка заголовков
Cake\Http\Response::withHeader($header, $value)
Настройка заголовков выполняется с помощью метода Cake\Http\Response::withHeader(). Как и все методы интерфейса PSR-7, этот метод возвращает экземпляр new с новым заголовком:
Заголовки не отправляются при установке. Вместо этого они сохраняются до тех пор, пока не будет получен ответ Cake\Http\Server.
Теперь вы можете использовать удобный метод Cake\Http\Response::withLocation(), чтобы напрямую установить или получить заголовок местоположения перенаправления.
Настройка body
Cake\Http\Response::withStringBody($string)
Чтобы установить строку в качестве тела ответа, необходимо выполнить следующие действия:
Использование произвольных методов HTTP запроса
Мы уже рассмотрели (здесь) методы GET, PUT, HEAD, OPTIONS и другие. На самом деле, в качестве метода можно указать что угодно. Метод указывается после опции -X
Не все серверы одинаково реагируют на произвольные методы, например, команда:
curl -X 'HACK' -A 'Chrome' https://hackware.ru
вызовет ошибку «403 Forbidden».
Команда
curl -X 'HACK' -A 'Chrome' 87.236.16.208
вызовет ошибку «501 Not Implemented».
Команда на этот же сервер, но на 443 порт вместо 80:
curl -X 'HACK' -A 'Chrome' https://87.236.16.208 -k
вызовет ошибку веб-сервера «502 Bad Gateway».
Но современные веб-серверы Apache 2.4 с настройками по умолчанию просто обрабатывают незнакомые методы как если бы это был GET.
Проверим на нашем локальном сервере:
curl -v -H 'Hackware: Hello! How are you?' -X 'MIAL' localhost/headers.php
Как можно убедиться, несмотря на то, что строка запроса стала такой:
MIAL /headers.php HTTP/1.1
Веб-сервер и скрипт корректно обработали этот запрос и прислали ожидаемые данные.
Кажется, что всё как обычно, но такой запрос уже невозможно найти в Wireshark по фильтру
http
Продемонстрируем это скриншотами.
Поиск по фильтру «http» после выполнения команды с запросом методом GET:
curl -H 'Hackware: Hello! How are you?' localhost/headers.php
Всё как положено: HTTP запрос и ответ присутствуют.
Поиск по фильтру «http» после выполнения команды с запросом методом MIAL:
curl -H 'Hackware: Hello! How are you?' -X 'MIAL' localhost/headers.php
То есть ответ найден (потому что он обычный), а запрос уже нет.
POST несколько файлов с многократным кодированием¶
Вы можете отправить несколько файлов в одном запросе. Например, предположим,
что вы хотите загрузить файлы изображений в HTML-форму с несколькими полями
файлов «images»:
<input type="file" name="images" multiple="true" required="true"/>
Для этого достаточно прописать файлы в список кортежей :
>>> url = 'https://httpbin.org/post' >>> multiple_files = ... ('images', ('foo.png', open('foo.png', 'rb'), 'image/png')), ... ('images', ('bar.png', open('bar.png', 'rb'), 'image/png'))] >>> r = requests.post(url, files=multiple_files) >>> r.text { ... 'files': {'images': 'data:image/png;base64,iVBORw ....'} 'Content-Type': 'multipart/form-data; boundary=3131623adb2043caaeb5538cc7aa0b3a', ... }
Пользовательская аутентификация¶
Requests позволяет указать собственный механизм аутентификации.
У любого вызываемого объекта, который передаётся как аргумент методу
запроса, будет возможность изменить запрос перед его отправкой.
Реализации аутентификации являются подклассами , и их легко определить. Requests предоставляет две
общие реализации схемы аутентификации в : и .
Представим, что у нас есть веб-служба, которая будет отвечать только в том
случае, если в заголовке установлено значение пароля. Маловероятно,
но просто смиритесь.
from requests.auth import AuthBase class PizzaAuth(AuthBase): """Присоединяет HTTP-аутентификацию Pizza к заданному объекту запроса.""" def __init__(self, username): # настройте здесь любые данные, связанные с авторизацией self.username = username def __call__(self, r): # изменить и возвращает запрос r.headers'X-Pizza' = self.username return r
Затем мы можем сделать запрос, используя нашу Pizza Auth:
Использование прокси
Аргумент proxies используется для настройки прокси-сервера для использования в ваших запросах.
http = "http://10.10.1.10:1080" https = "https://10.10.1.11:3128" ftp = "ftp://10.10.1.10:8080" proxy_dict = { "http": http, "https": https, "ftp": ftp } r = requests.get('http://sampleurl.com', proxies=proxy_dict)
Библиотека запросов также поддерживает прокси SOCKS. Это дополнительная функция, и она требует, чтобы перед использованием была установлена зависимость requests . Как и раньше, вы можете установить его с помощью pip:
$ pip install requests
После установки вы можете использовать его:
proxies = { 'http': 'socks5:user::port' 'https': 'socks5:user::port' }
Получить содержимое страницы (GET)
Самый простой и обычный HTTP-запрос — получить содержимое заданного URL. URL может ссылаться на веб-страницу, изображение или какой либо-другой файл. Клиент отсылает GET-запрос на сервер и получает запрашиваемый документ. Если выполнить команду
$ curl http://curl.haxx.se
вы получите веб-страницу, выведенную в окно терминала (точнее, в стандартный вывод). Чтобы сохранить эту страницу в файл , нужно указать
$ curl http://curl.haxx.se -o "curl.html"
Все HTTP-ответы содержат набор заголовков, которые обычно скрыты. Чтобы увидеть эти заголовки вместе с самим документом, используйте ключ .
Команда nslookup
Эта команда также позволяет получить информацию по домену или по IP адресу. Основной синтаксис написания nslookup:
nslookup
где — указывать необязательно.
Самый простой пример использования nslookup приведем ниже:
nslookup freehost.com.ua
Можем выполнить и обратную задачу — по IP адресу узнать доменное имя сайта.
nslookup 194.0.200.202
Ниже приведем основные опции команды nslookup:
- type – записывается тип записи DNS (к примеру, NS, TXT, SOA и др.);
- port – указывается номер порта;
- recurse – в случае, когда DNS не отвечает, использовать другие DNS;
- retry – задается количество попыток;
- timeout – время;
- fail – в случае, когда DNS возвращает ошибку, необходимо использовать другой сервер.
Приведем примеры команды, с использованием опции type (тип записи), например, для получения записей типа NS, MX, TXT, SOA и т.д.:
nslookup -type=ns freehost.com.ua nslookup -type=mx freehost.com.ua nslookup -type=txt freehost.com.ua nslookup -type=soa freehost.com.ua
Техническую информацию о домене можно получить в ответе, запустив команду nslookup с параметром для типа записи SOA:
- origin — источник информации;
- mail addr — указывает email address администратора домена;
- serial — показывает время в формате timestamp;
- refresh — выводит время в секундах, в течении которого нужно повторить подключения, чтобы обновить информацию;
- retry — указывает время в секундах, через которое необходимо опять повторить подключения к DNS, в случае, если он недоступен;
- expire — показывает интервал времени в секундах, через который нужно считать информацию, полученную от первого DNS, устаревшей;
- minimum — это время в секундах, которое проходит до следующего обновления.