Справочник · Веб и HTTP
curl: запросы из командной строки
GET и POST, JSON и формы, заголовки, авторизация, cookie, загрузка файлов, перенаправления, повторы и замер времени ответа. Всё, что нужно для проверки API без графических клиентов.
curl есть почти везде: на серверах, в контейнерах, в macOS и Windows 10 и новее. Им удобно проверять API, скачивать файлы и выяснять, что именно отвечает сервер. В примерах ниже адрес лежит в переменной: так короче и так же удобно в скриптах.
API=localhost:8080/apiПростые запросы
curl $API/users # GET, тело ответа в терминал
curl -i $API/users # с заголовками ответа
curl -I $API/users # только заголовки (метод HEAD)
curl -s $API/users # без индикатора прогресса
curl -sS $API/users # тихо, но ошибки показывать
curl -o users.json $API/users # сохранить в файл
curl -v $API/users # подробно: заголовки запроса и ответа, TLS
curl "$API/users?page=2&limit=50" # параметры в кавычкахПараметры строки запроса можно не склеивать руками: -G вместе с --data-urlencode соберёт и закодирует их сам.
curl -G $API/search --data-urlencode "q=привет мир" --data-urlencode "lang=ru"
# уйдёт GET /api/search?q=%D0%BF%D1%80%D0%B8...&lang=ruКак устроено процентное кодирование, видно в URL-кодировщике.
Самые нужные ключи
| Ключ | Что делает |
|---|---|
-X METHOD | метод запроса: POST, PUT, PATCH, DELETE |
-H "Имя: значение" | добавить заголовок, можно несколько раз |
-d 'данные' | тело запроса; сам ставит метод POST |
-d @file.json | тело из файла |
--json '...' | тело JSON с нужными заголовками (curl 7.82 и новее) |
-F name=value | поле формы multipart/form-data |
-F file=@photo.jpg | загрузка файла |
-u user:pass | Basic-авторизация |
-L | идти по перенаправлениям |
-o file / -O | сохранить в файл / под именем из адреса |
-C - | докачать прерванную загрузку |
-s / -S | тихий режим / но показывать ошибки |
-f или --fail | при ответе 4xx и 5xx вернуть ненулевой код выхода |
-w '...' | вывести сведения после запроса: код, время, размер |
-m 10 | ограничить всю операцию десятью секундами |
--connect-timeout 3 | ограничить только установку соединения |
--retry 3 | повторить при временных ошибках |
-b / -c | отправить cookie / сохранить полученные cookie в файл |
-k | не проверять сертификат (только для отладки) |
--compressed | попросить сжатый ответ и распаковать его |
JSON
# классический способ
curl -X POST $API/users \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{"name": "Анна", "role": "admin"}'
# то же короче, curl сам выставит оба заголовка и метод
curl --json '{"name": "Анна", "role": "admin"}' $API/users
# тело из файла
curl --json @user.json $API/users
# частичное обновление и удаление
curl -X PATCH --json '{"role": "viewer"}' $API/users/42
curl -X DELETE $API/users/42Ключ -d отправляет данные как есть, но выбрасывает переводы строк, если читает из файла через @. Для бинарных данных и файлов, где переводы строк важны, используйте --data-binary @file.
Подставлять переменные оболочки внутрь JSON в одинарных кавычках нельзя: они не раскроются. Надёжнее собрать тело через jq:
name="Анна \"Ника\""
jq -n --arg name "$name" '{name: $name, active: true}' | curl --json @- $API/users@- означает «прочитать тело со стандартного ввода».
Формы и файлы
# обычная форма: application/x-www-form-urlencoded
curl -d "login=anna" -d "remember=1" $API/login
# значение с пробелами и спецсимволами — с кодированием
curl --data-urlencode "comment=Цена 100% & доставка" $API/feedback
# multipart: поля и файлы
curl -F "title=Отчёт" -F "file=@report.pdf" $API/upload
curl -F "file=@photo.jpg;type=image/jpeg;filename=avatar.jpg" $API/avatar
# загрузить файл телом запроса, как делают хранилища объектов
curl -T backup.tar.gz $API/files/backup.tar.gzЗаголовки и авторизация
curl -H "Authorization: Bearer $TOKEN" $API/me
curl -u anna:secret $API/admin # Basic, curl сам закодирует в Base64
curl -u anna $API/admin # пароль спросит интерактивно
curl -H "X-Request-Id: $(uuidgen)" $API/orders
curl -H "Accept-Language: ru" $API/products
curl -A "my-script/1.0" $API/ping # свой User-AgentСтроку Basic из заголовка можно раскодировать декодером Base64, а содержимое Bearer-токена в формате JWT показывает разбор JWT.
Cookie и сессии
# войти и сохранить cookie в файл
curl -c cookies.txt -d "login=anna&password=secret" $API/login
# следующие запросы с этими cookie
curl -b cookies.txt $API/profile
# читать и обновлять одновременно
curl -b cookies.txt -c cookies.txt $API/cart
# передать cookie напрямую
curl -b "sid=a1b2c3; theme=dark" $API/profileПеренаправления и скачивание
curl -L $API/old-path # пройти по всем перенаправлениям
curl -L --max-redirs 5 $API/old-path
curl -sIL $API/old-path | grep -i -E "^(HTTP|location)" # показать цепочку
curl -LO "$URL" # скачать под исходным именем
curl -L -o app.tar.gz -C - "$URL" # докачать, если файл уже частично есть
curl -L --limit-rate 2M -O "$URL" # не быстрее 2 МБ/сПо умолчанию curl не идёт по перенаправлениям и показывает ответ 301 или 302 как есть. Если скачанный «файл» весит пару сотен байт, загляните в него: скорее всего это страница перенаправления.
Скрипты: коды, повторы, таймауты
В скриптах важно, чтобы ошибка HTTP не выглядела как успех. Без --fail curl возвращает код выхода 0 даже на ответ 500.
if ! curl -fsS -m 10 -o /dev/null "$API/health"; then
echo "сервис не отвечает" >&2
exit 1
fiТолько код ответа:
code=$(curl -s -o /dev/null -w '%{http_code}' "$API/health")
[[ "$code" == 200 ]] || echo "получили $code"Повторы при временных сбоях:
curl -fsS --retry 5 --retry-delay 2 --retry-all-errors -m 30 "$API/report" -o report.json--retry сам по себе повторяет только при сетевых ошибках, таймаутах и ответах 408, 429, 500, 502, 503 и 504. --retry-all-errors (curl 7.71 и новее) повторяет при любой ошибке; пользуйтесь им осторожно с запросами, которые что-то меняют.
| Код выхода curl | Значение |
|---|---|
| 0 | успех |
| 6 | не удалось найти адрес по имени (DNS) |
| 7 | не удалось подключиться |
| 22 | сервер ответил 400 или больше, при --fail |
| 28 | истёк таймаут |
| 35 | ошибка TLS-соединения |
| 60 | сертификат сервера не прошёл проверку |
Сколько времени занимает запрос
Ключ -w выводит переменные после завершения запроса. Удобно разложить время по этапам:
curl -s -o /dev/null -w '
dns: %{time_namelookup}s
connect: %{time_connect}s
tls: %{time_appconnect}s
first byte:%{time_starttransfer}s
total: %{time_total}s
code: %{http_code}
size: %{size_download} байт
' "$API/products"Если основная часть времени уходит до первого байта, медленно работает приложение. Если велик connect или tls, дело в сети или настройке TLS. Шаблон можно положить в файл и подключать как -w @timing.txt.
Полезные мелочи
--resolve api.local:443:127.0.0.1отправит запрос на указанный IP, сохранив имя хоста в TLS иHost. Так проверяют новый сервер до переключения DNS.-H "Host: site.local"делает то же для обычного HTTP.--http1.1и--http2принудительно выбирают версию протокола.-K config.txtчитает ключи из файла; удобно для длинных повторяющихся команд.curl --versionпоказывает версию и поддерживаемые возможности: если какого-то ключа нет, причина обычно здесь.- В браузере в инструментах разработчика, во вкладке «Сеть», у любого запроса есть пункт «Копировать как cURL». Получится готовая команда со всеми заголовками и cookie, только не публикуйте её: в ней могут быть токены.
Что означают коды ответа, разобрано в отдельной статье, а заголовки — в статье про заголовки HTTP.