Доброго времени суток, друзья!
Представляю Вашему вниманию перевод статьи What JavaScript Developers Should Know About Curl автора Valery Karpov.
Curl это популярный инструмент командной строки, часто используемый для отправки HTTP-запросов. Curl поддерживает большое количество протоколов, однако как Node.js-разработчик вы, скорее всего, будете использовать его для отпраки http-запросов к RESTful API.
Документация curl представляет собой перечень из 383 флагов командной строки, поэтому в ней очень трудно найти то, что ищешь. В этой статье я хочу поделиться с вами некоторыми часто используемыми мной шаблонами. Для примеров будет использоваться сервис httpbin.org.
Отправка http-запроса
Для начала убедитесь в том, что у вас установлен curl, выполнив команду
curl --version
.
$ curl --versioncurl 7.58.0 (x86_64-pc-linux-gnu) libcurl/7.58.0 OpenSSL/1.1.1 zlib/1.2.11 libidn2/2.0.4 libpsl/0.19.1 (+libidn2/2.0.4) nghttp2/1.30.0 librtmp/2.3Release-Date: 2018-01-24Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtmp rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IDN IPv6 Largefile GSS-API Kerberos SPNEGO NTLM NTLM_WB SSL libz TLS-SRP HTTP2 UnixSockets HTTPS-proxy PSL
Для отправки запроса необходимо запустить
curl url
.
Например, для отправки GET-запроса к
https://httpbin.org/get?answer=42
следует запустить
curl https://httpbin.org/get?answer=42
.
$ curl https://httpbin.org/get?answer=42{ "args": { "answer": "42" }, "headers": { "Accept": "*/*", "Host": "httpbin.org", "User-Agent": "curl/7.58.0", "X-Amzn-Trace-Id": "Root=1-5ee8d737-b39c6a466892725bbb52b916" }, "origin": "69.84.111.39", "url": "https://httpbin.org/get?answer=42"}
После успешного завершения запроса curl возвращает тело http-ответа. Для того, чтобы заставить curl вернуть весь ответ, включая заголовки, используйте флаг -i.
$ curl -i https://httpbin.org/get?answer=42HTTP/2 200 date: Tue, 16 Jun 2020 14:30:57 GMTcontent-type: application/jsoncontent-length: 801server: istio-envoyaccess-control-allow-origin: *access-control-allow-credentials: truex-envoy-upstream-service-time: 2{ "args": { "answer": "42" }, "headers": { "Accept": "*/*", "Content-Length": "0", "Host": "httpbin.org", "User-Agent": "curl/7.58.0", "X-Amzn-Trace-Id": "Root=1-5ee8d7a1-cb3954c09299eb9e0dff70a6", "X-B3-Parentspanid": "dffc55451e64b5fc", "X-B3-Sampled": "0", "X-B3-Spanid": "8e233a863fb18b6c", "X-B3-Traceid": "45bd12a9067fb5c0dffc55451e64b5fc", "X-Envoy-External-Address": "10.100.91.201", "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin-istio/sa/httpbin;Hash=c1ff14671b3e24ee794f9a486570abf8ccc9d622846611d3f91a322db4d480cd;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account" }, "origin": "69.84.111.39,10.100.91.201", "url": "http://httpbin.org/get?answer=42"}
Это полный http-ответ. Заголовками ответа являются строки от
date:
до
x-envoy-upstream-service-time:
.Загрузка файлов
Wget самый распространенный инструмент для загрузки файлов посредством командной строки. Он входит в комплект большинства диструбутивов Linux. Однако в OSX его нет.
Команда
wget url
аналогична команде curl -OL
url
. Опция -О
это опция
--remote-name
, которая говорит curl сохранить тело
ответа в локальном файле. Опция -L
говорит curl
следовать перенаправлениям.Например, ниже представлено изображение с Unsplash, его URL
https://images.unsplash.com/photo-1506812574058-fc75fa93fead
.Для загрузки этого изобюражения необходимо выполнить следующее:
$ curl -OL https://images.unsplash.com/photo-1506812574058-fc75fa93fead % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 12.1M 100 12.1M 0 0 3927k 0 0:00:03 0:00:03 --:--:-- 3927k
Опция
-O
говорит curl использовать строку после
последнего /
в качестве имени файла. В приведенном
примере изображение будет сохранено в текущей директории с именем
photo-1506812574058-fc75fa93fead
. Для определения
имени файла используйте опцию -о
(строчная буква
о).
$ curl -o miami-beach.jpg https://images.unsplash.com/photo-1506812574058-fc75fa93fead % Total % Received % Xferd Average Speed Time Time Time Current Dload Upload Total Spent Left Speed100 12.1M 100 12.1M 0 0 6083k 0 0:00:02 0:00:02 --:--:-- 6083k$ ls -l miami-beach-jpg-rw-rw-r-- 1 val val 12788445 Jun 16 11:03 miami-beach.jpg
Отправка авторизованного запроса
Заголовок авторизации используется для включения в запрос данных для авторизации при обращении к RESTful API. Для добавления указанных данных необходимо использовать флаг
-H
.
Например, если ваш ключ интерфейса (API key)
my-secret-token
, вы можете включить его в http-запрос
следующим образом:
$ curl -H "Authorization: my-secret-token" https://httpbin.org/get{ "args": {}, "headers": { "Accept": "*/*", "Authorization": "my-secret-token", "Host": "httpbin.org", "User-Agent": "curl/7.58.0", "X-Amzn-Trace-Id": "Root=1-5ee8e1a5-a3aa30e0765a7980b04ca4a0" }, "origin": "69.84.111.39", "url": "https://httpbin.org/get"}
Обратите внимание, что
httpbin.org
возвращает
заголовки http-запроса в теле ответа в свойстве
headers
.Curl также поддерживает авторизацию по-умолчанию посредством флага
-u
. В следующем примере мы отправляем запрос с именем
пользователя user
и паролем pass
:
$ curl -i -u "user:pass" https://httpbin.org/basic-auth/user/passHTTP/2 200 date: Tue, 16 Jun 2020 15:18:45 GMTcontent-type: application/jsoncontent-length: 47server: istio-envoyaccess-control-allow-origin: *access-control-allow-credentials: truex-envoy-upstream-service-time: 1{ "authenticated": true, "user": "user"}
Вот что происходит при отправке неправильного имени пользователя или пароля:
$ curl -i -u "user:wrongpass" https://httpbin.org/basic-auth/user/passHTTP/2 401 date: Tue, 16 Jun 2020 15:18:51 GMTcontent-length: 0server: istio-envoywww-authenticate: Basic realm="Fake Realm"access-control-allow-origin: *access-control-allow-credentials: truex-envoy-upstream-service-time: 12
Отправка POST-запроса, содержащего JSON
Флаг
-X
говорит curl, какой метод следует
использовать: PUT, POST и т.д. По-умолчанию curl использует метод
GET, поэтому писать curl -X GET
не нужно.Флаг
-X
часто используется совместно с флагом
-d
, позволяющим добавить тело запроса. В следующем
примере показано как отправить POST-запрос, содержащий некоторый
json:
$ curl -X POST -d '{"answer":42}' https://httpbin.org/post{ "args": {}, "data": "", "files": {}, "form": { "{\"answer\":42}": "" }, "headers": { "Accept": "*/*", "Content-Length": "13", "Content-Type": "application/x-www-form-urlencoded", "Host": "httpbin.org", "User-Agent": "curl/7.58.0", "X-Amzn-Trace-Id": "Root=1-5ee8e3fd-8437029087be44707bd15320", "X-B3-Parentspanid": "2a739cfc42d28236", "X-B3-Sampled": "0", "X-B3-Spanid": "8bdf030613bb9c8d", "X-B3-Traceid": "75d84f317abad5232a739cfc42d28236", "X-Envoy-External-Address": "10.100.91.201", "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin-istio/sa/httpbin;Hash=ea8c3d70befa0d73aa0f07fdb74ec4700d42a72889a04630741193548f1a7ae1;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account" }, "json": null, "origin": "69.84.111.39,10.100.91.201", "url": "http://httpbin.org/post"}
Обратите внимание, что по-умолчанию значением заголовка
Content-Type
является
application/x-www-form-urlencoded
. Для json это
является неверным, поэтому для определения
Content-Type
следует использовать флаг
-H
:
$ curl -X POST -d '{"answer":42}' -H "Content-Type: application/json" https://httpbin.org/post{ "args": {}, "data": "{\"answer\":42}", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Content-Length": "13", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "curl/7.58.0", "X-Amzn-Trace-Id": "Root=1-5ee8e45e-ad875af4f83efd4379b86c34", "X-B3-Parentspanid": "5f4f33d1c5ea13aa", "X-B3-Sampled": "0", "X-B3-Spanid": "a062c9bf2ebfd4bd", "X-B3-Traceid": "44aa8d62412ae34d5f4f33d1c5ea13aa", "X-Envoy-External-Address": "10.100.86.47", "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin-istio/sa/httpbin;Hash=2f0b3331fe4d512975b4b82583a55dd5d1196023d0dfce9e0abed246991c5b67;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account" }, "json": { "answer": 42 }, "origin": "69.84.111.39,10.100.86.47", "url": "http://httpbin.org/post"}
Отправка PUT-запроса, содержащего JSON-файл
Флаг
-d
также поддерживает отправку данных из
локальных файлов.Например, представим, что у нас есть файл
data.js
,
содержащий такие данные:
{"answer": 42}
Для отправки PUT-запроса с этим файлом в качестве тела запроса вы можете присвоить флагу
-d
значение
@data.json
. Префикс @
говорит curl
загрузить тело запроса из файла data.json
:
$ curl -X PUT -d '@data.json' -H "Content-Type: application/json" https://httpbin.org/put{ "args": {}, "data": "{\"answer\":42}", "files": {}, "form": {}, "headers": { "Accept": "*/*", "Content-Length": "13", "Content-Type": "application/json", "Host": "httpbin.org", "User-Agent": "curl/7.58.0", "X-Amzn-Trace-Id": "Root=1-5ee8e745-37c4ef06326b7b4354a16b94", "X-B3-Parentspanid": "a4f8f91f4f1b051e", "X-B3-Sampled": "0", "X-B3-Spanid": "a018b1a3fcebdc68", "X-B3-Traceid": "7b48b01dc3f632eea4f8f91f4f1b051e", "X-Envoy-External-Address": "10.100.91.201", "X-Forwarded-Client-Cert": "By=spiffe://cluster.local/ns/httpbin-istio/sa/httpbin;Hash=6035260d9d551af6c1907270653214e8d3195abbdd19078c1c84fd9a4106f260;Subject=\"\";URI=spiffe://cluster.local/ns/istio-system/sa/istio-ingressgateway-service-account" }, "json": { "answer": 42 }, "origin": "69.84.111.39,10.100.91.201", "url": "http://httpbin.org/put"}
Заключение
Резюмируя, вот опции curl, которые я нахожу самыми полезными:
-
-X
определяет метод запроса, например,curl -X POST url
-
-d
определяет тело запроса в виде строки в PUT и POST-запросах. Используйте@
для извлечения данных из файла -
-H
определяет заголовок запроса, например,curl -H "Authorization: my-secret-token" url
-
-u
аутентификационные данные для стандартной авторизации -
-O
сохраняет тело запроса в файл -
-i
показывает полный ответ, включая заголовки
Curl полезный инструмент взаимодействия с API посредством командной строки, независимо от того, сторонний это API или API, который вы разрабатываете. Для быстрого тестирования curl подходит лучше, чем Axios в Node.js или настройка запроса в Postman, если вы знакомы с их синтаксисом.
Благодарю за потраченное время. Надеюсь, оно было потрачено не зря.