← Весь справочник

curl

HTTP-запросы из терминала — заголовки, коды ответа, POST с телом, редиректы, HTTPS, замеры времени

curl отправляет запрос по URL и печатает тело ответа в stdout. Это главный способ проверить веб-сервер или API из консоли: что он отвечает, с каким кодом и какими заголовками, сколько времени занял запрос.

Синтаксис

curl [опции] URL…

Без опций curl делает GET и выводит тело. Метод, заголовки и тело задаются флагами. Короткие флаги можно склеивать: -sSfL = -s -S -f -L.

Вывод и сохранение

ОпцияЧто делает
-sтихий режим: без индикатора прогресса и без сообщений об ошибках
-Sвместе с -s всё-таки показывает ошибки — пара -sS
-o файлсохранить тело в файл; -o /dev/null — выбросить
-Oсохранить под именем из URL (последний сегмент пути)
-Jвместе с -O: взять имя из заголовка Content-Disposition
-C -докачать файл с места обрыва
-iпоказать заголовки ответа вместе с телом
-Iзапрос HEAD: только заголовки ответа
-D файлзаписать заголовки ответа в файл; -D - — в stdout
-w 'формат'после запроса напечатать переменные (см. ниже); -w @файл — формат из файла
-fпри коде 400 и выше не печатать тело, код выхода 22
--fail-with-bodyкак -f, но тело ошибки печатается

Метод, заголовки, тело

ОпцияЧто делает
-X МЕТОДзадать метод: PUT, DELETE, PATCH…
-H 'Имя: значение'добавить заголовок; можно повторять. -H 'Имя:' — убрать заголовок, который curl ставит сам
-A 'строка'заголовок User-Agent
-e URLзаголовок Referer
-b 'k=v' / -b файлотправить cookie строкой или из файла
-c файлсохранить полученные cookie в файл (cookie jar)
-d 'данные'тело запроса; делает POST с application/x-www-form-urlencoded. -d @файл — из файла, переводы строк выкидываются
--data-binary @файлтело из файла байт в байт
--data-raw 'данные'как -d, но @ в начале — обычный символ
--data-urlencode 'k=v'закодировать значение для URL (пробел → +, & → %26)
-Gпревратить все -d в параметры строки запроса и отправить GET
--json 'JSON'тело JSON и заголовки Content-Type/Accept: application/json (curl 7.82+)
-F 'k=v' / -F 'file=@путь'форма multipart/form-data, загрузка файла
-T файлзагрузить файл методом PUT
--compressedпопросить сжатый ответ и распаковать его

Авторизация и TLS

ОпцияЧто делает
-u логин:парольBasic-авторизация; -u логин — пароль спросит
-H 'Authorization: Bearer ТОКЕН'токен-авторизация
-kне проверять сертификат сервера
--cacert ca.pemдоверять этому CA (для своего или самоподписанного сертификата)
--cert cert.pem --key key.pemклиентский сертификат (mTLS)

Сеть, редиректы, таймауты

ОпцияЧто делает
-Lидти по редиректам (301, 302…); --max-redirs N — не больше N переходов
--resolve хост:порт:IPдля этого хоста и порта ходить на указанный IP, минуя DNS
--connect-to хост:порт:новый_хост:новый_портподключаться к другому адресу, оставив в запросе исходное имя
-x http://прокси:портчерез прокси; --noproxy '*' — игнорировать переменные http_proxy
-4 / -6только IPv4 / только IPv6
--connect-timeout Nждать соединения не больше N секунд
-m N / --max-time Nвесь запрос не дольше N секунд (код выхода 28)
--retry Nповторить при временных ошибках; --retry-delay S, --retry-connrefused — и при отказе в соединении
--http1.1 / --http2версия протокола

Отладка

ОпцияЧто делает
-vзаголовки запроса (>), ответа (<), служебные строки (*): DNS, подключение, TLS
--trace-ascii файлполный дамп обмена, включая тело; - — в stdout

Переменные для -w

ПеременнаяЧто значит
%{http_code}код ответа (000, если ответа не было)
%{time_namelookup}, %{time_connect}, %{time_appconnect}время до окончания DNS, TCP-подключения, TLS-рукопожатия (секунды, от начала)
%{time_starttransfer}время до первого байта ответа (TTFB)
%{time_total}полное время запроса
%{size_download}, %{content_type}размер тела в байтах, тип содержимого
%{remote_ip}, %{remote_port}куда реально подключились
%{redirect_url}куда указывает редирект (без -L)
%{url_effective}, %{num_redirects}итоговый URL и число переходов (с -L)
%{ssl_verify_result}результат проверки сертификата: 0 — успешно
%header{имя}значение заголовка ответа (curl 7.84+)
%{exitcode}, %{errormsg}код ошибки curl и её текст (curl 7.75+)
%{json}все переменные одним JSON-объектом

Коды выхода

0 — ответ получен (любой, даже 500, если нет -f), 6 — не удалось разрешить имя, 7 — не удалось подключиться, 22 — HTTP-ошибка при -f, 28 — таймаут, 35 — ошибка TLS-рукопожатия, 47 — превышен --max-redirs, 60 — сертификат не прошёл проверку.

Примеры

# только код ответа — удобно в скриптах и проверках
curl -s -o /dev/null -w '%{http_code}\n' http://localhost/

# заголовки ответа без тела
curl -I http://localhost/

# заголовки и тело реального GET-запроса
curl -si http://localhost/

# куда и за сколько: DNS, подключение, первый байт, всё вместе
curl -s -o /dev/null -w 'dns=%{time_namelookup} conn=%{time_connect} ttfb=%{time_starttransfer} total=%{time_total}\n' http://localhost/

# скачать файл, следуя редиректам; ошибки показать, прогресс скрыть
curl -sSL -o archive.tar.gz https://example.com/archive.tar.gz

# POST с JSON
curl -s -H 'Content-Type: application/json' -d '{"name":"demo"}' http://localhost:8000/api/items

# GET с параметрами, закодированными как надо
curl -s -G --data-urlencode 'q=a b&c' -d page=2 http://localhost:8000/search

# загрузить файл формой
curl -s -F 'file=@report.pdf' -F 'title=Отчёт' http://localhost:8000/upload

# удалить ресурс
curl -s -X DELETE http://localhost:8000/api/items/1

# Basic-авторизация и свой заголовок
curl -s -u admin:secret -H 'Accept: application/json' http://localhost:8000/

# залогиниться, сохранив cookie, и пойти с ними дальше
curl -s -c cookies.txt -d 'user=demo&pass=demo' http://localhost:8000/login
curl -s -b cookies.txt http://localhost:8000/profile

# проверить виртуальный хост, не трогая DNS и /etc/hosts
curl -s --resolve example.com:80:127.0.0.1 http://example.com/

# HTTPS с самоподписанным сертификатом: лучше --cacert, чем -k
curl -s --cacert cert.pem https://localhost:8443/

# значение одного заголовка ответа
curl -s -o /dev/null -w '%header{content-type}\n' http://localhost/

# упасть с ненулевым кодом выхода, если сервер ответил ошибкой
curl -sSf --max-time 5 http://localhost/health || echo 'сервис не отвечает'

Подводные камни

  • Без -f код выхода 0 даже на 404 и 500. curl считает успехом сам факт ответа. Для проверок бери -f или явно сравнивай %{http_code}.
  • -s глотает и ошибки. curl -s на упавший сервер ничего не напишет. Добавляй -S, чтобы видеть причину (Couldn't connect to server, SSL certificate problem).
  • -d @файл убирает переводы строк. Для многострочного JSON, бинарных данных и вообще «отправить файл как есть» нужен --data-binary @файл.
  • -d без Content-Type уходит как application/x-www-form-urlencoded. API, который ждёт JSON, такой запрос не поймёт — добавь заголовок или используй --json.
  • -X POST не добавляет тело, а -d уже делает запрос POST. А -X вместе с -L применяется ко всем переходам — после 302 сервер ждёт GET, а получит снова POST.
  • Без -L редирект не выполняется: получишь 301 и короткую страницу-заглушку. Смотри -w '%{redirect_url}' или -i, куда ведёт переход.
  • -I — это HEAD, а не GET. Некоторые приложения отвечают на HEAD иначе. Чтобы увидеть заголовки настоящего GET, используй -i, -D - или -v.
  • -k отключает защиту целиком. Для своего сертификата лучше --cacert cert.pem: проверка останется, просто с твоим доверенным корнем.
  • Спецсимволы в URL. & и ? в URL без кавычек разрежет оболочка — бери URL в кавычки.
  • -O не работает, если URL кончается на / — имени файла нет. Тогда задай имя через -o.

См. также

nginx · openssl · jq · dig · ss