普段インターネット上のWeb サイトを閲覧する際にはChrome などのいわゆるWeb ブラウザを使いますが、開発者やシステム管理者に広く使われるWeb アクセスの手法として欠かせないツールの1つがcurl です。本記事では、curl コマンドの典型的な使い方やよく使われるオプションをユースケースとともに紹介します。
目次
curl の基本
もっとも基本的な使い方としては、単純に引数としてWeb サイトのURL を与えます。
$ curl http://example.com
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
curl コマンドで生のHTML が取得できました。もちろん、通常通りWeb ブラウザでアクセスすればもっと見やすい形でアクセスできます。
ここで行われている実際の裏の動作としては、curl コマンドでは公開されているWeb サイトに対して必要に応じて名前解決を行い、宛先IP アドレスに対してHTTP GET リクエストを送信し、その結果をターミナルに出力しています。ブラウザでも同様に http://example.com に対してGET リクエストを送信し、ブラウザによってユーザーが見やすい形にHTML が整形されています。
このように、単純なWeb サイトの閲覧目的では普通にブラウザを使うべきです。curl はシンプルがゆえに、特にAPI のテストや自動化、スクリプトの作成といったブラウザでは難しい幅広い用途で利用できます。
その例として、先ほどはGET リクエストを送信しましたが、今度はPOST リクエストを実行してみましょう。POST リクエストとは、簡単に言うとGET の反対、つまりデータの受信ではなく送信にあたります。イメージしやすいものとしては、Web サイトのフォーム入力でしょう。例えばあるWeb サイトのフォームにテキストを入力し送信する場合、POST リクエストが実行され、データがクライアントからWeb サーバーに送信されることになります。厳密にはGET リクエストでもWeb サーバーに対してパラメータを送信することができますが、POST の方が何かと都合がよいです。
POST のテストとして、https://httpbin.org/post を使います。このサービスは、ブラウザで直接アクセスする場合はGET リクエストが許可されていないため405 Method Not Allowed エラーが出ますが、curl で直接POST リクエストを実行することで、データを送信し、送信した内容をJSON で受け取ることができます。
$ curl -X POST https://httpbin.org/post -d "param1=value1¶m2=value2"
{
"args": {},
"data": "",
"files": {},
"form": {
"param1": "value1",
"param2": "value2"
},
"headers": {
"Accept": "*/*",
"Content-Length": "27",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-65bb2e78-2648b85f07e07b5a0b1e2ddd"
},
"json": null,
"origin": "192.168.1.1",
"url": "https://httpbin.org/post"
}
ここで、オプションの-X はHTTP リクエストのメソッド(GET やPOST など。http://example.com にGET リクエストをした際には省略されていました)を明示的に指定していて、-d はボディとして送信するコンテンツになります。
これは単純にデータを1回テストサイトに送信する例ですが、例えば構築したWeb アプリケーションに対してテスト目的で100回データを送信したい場合に、curl を使う場合はループを使って連続で実行できたりするので、効率よくテストをすることができます。そういった意味では、冒頭に説明した通り一般のユーザーにとってはあまり用途はないかもしれませんが、システム管理者や開発者にとってはcurl はとてもありがたいものになります。
典型的なオプションとユースケース
すでにいくつか紹介していますが、curl はオプションが豊富です。普段なかなか使わないものもありますので、ここではいくつか典型的なオプションを紹介します。
-X (--request)
先ほど紹介しましたが、メソッドを明示的に指定できます。ユースケースとしては、POST リクエストやPUT リクエストなど任意のメソッドを使う場合です。例えばPOST メソッドの場合は先述した通り-d オプションで送信するデータを含めることができます。なお-d オプションを使えばPOST ということが明示的にわかるため、-X オプションは不要です。
-k (--insecure)
個人的に一番お世話になったオプションです。暗号化通信のためのSSL/TLS 証明書の検証を無視して接続を強制するために使用されます。要するに、信頼できる証明書を使っていないとcurl がブロックされるWeb サイトでも接続できるようにすることができます。
ユースケースとしては、検証用のサーバーにアクセスする際に自己署名証明書を使っていて、証明書がきちんと信頼されたものではない場合にも接続したい場合に使います。公開前のサーバーは自己署名証明書で済ますことも多いので、そういった時には -k オプションが活躍します。
アクセスしようとしているサイトは自己署名証明書を使ったテストサイトです。エラーの通り、curl 使用時にエラーが出ています。
$ curl https://self-signed.badssl.com/
curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html
curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.
ブラウザで確認すると、確かに発行元と発行先が同じ組織でした。
そういった場合には-k オプションを使うとアクセスができます。
$ curl -k https://self-signed.badssl.com/
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="/icons/favicon-red.ico"/>
<link rel="apple-touch-icon" href="/icons/icon-red.png"/>
<title>self-signed.badssl.com</title>
<link rel="stylesheet" href="/style.css">
<style>body { background: red; }</style>
</head>
<body>
<div id="content">
<h1 style="font-size: 12vw;">
self-signed.<br>badssl.com
</h1>
</div>
</body>
</html>
ただし、このオプションは証明書エラーが発生したとしても安全であると自分で把握している場合に限り利用してください。例えばフィッシングサイトなどはしばしば証明書が不正だったりするケースがありますが(そもそも暗号化していないケースも多いのですが)、そういった意図的に証明書による安全性を確保していないサイトには-k オプションは使わないでください。
-H (--header)
カスタムヘッダーを指定します。ヘッダーとは、HTTP リクエストやレスポンスに付随するメタデータのようなものであり、リクエストが実行された時刻やメソッド、ユーザーエージェント(例えばどのブラウザからアクセスしてきたか)などの情報が含まれます。
ややとっつきづらいですが、実はとてもよく使います。典型的なユースケースとして認証を考えてみましょう。Web サービスへの認証方式は多数ありますが、その中にユーザー名とパスワードを使うシンプルなBasic 認証があります。curl は-u オプションによるBasic 認証を使えますので、下記のような感じでBasic 認証ができます(一部文字化けしていますが問題なく認証できています)。Basic 認証のテストには下記を利用しました。
https://leggiero.sakura.ne.jp/xxxxbasic_auth_testxxxx/
$ curl -u kaiin:naisho https://leggiero.sakura.ne.jp/xxxxbasic_auth_testxxxx/secret/kaiin_page_top.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<title>�閧�̉���y�[�W�g�b�v</title>
</head>
<body>
�閧�̉���y�[�W�ւ悤�����I
</body>
</html>
一方でBasic 認証では認証に求められるセキュリティなどの要件を満たさない場合があります。例えばJWT のようなBearer トークンベースの認証を使うことで、トークンの無効化や有効期限を設定することができ、より柔軟なアクセスコントロールが実現できます。その際にAuthorization ヘッダを設定することができる-H オプション使うことでそのようなトークンベースの認証が可能です。
$ curl -H "Authorization: Bearer YOUR_TOKEN" https://httpbin.org/bearer
{
"authenticated": true,
"token": "YOUR_TOKEN"
}
なお、補足として、先ほどのBasic 認証の場合は-u オプションを使いましたが、内部的には結局のところBase64 でエンコードしたユーザー名とパスワードをAuthorization ヘッダーのBasic スキームに入れて使っています。そのため-u ではなく-H オプションでもBasic 認証は可能です。
$ echo -n 'kaiin:naisho' | base64
a2FpaW46bmFpc2hv
$ curl -H "Authorization: Basic a2FpaW46bmFpc2hv" https://leggiero.sakura.ne.jp/xxxxbasic_auth_testxxxx/secret/kaiin_page_top.htm
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=Shift_JIS">
<title>�閧�̉���y�[�W�g�b�v</title>
</head>
<body>
�閧�̉���y�[�W�ւ悤�����I
</body>
</html>
そのほかのよく使うユースケースとしては、Content-Type ヘッダを設定し、送信するデータを明示的に指定する場合あります。下記はJSON データをPOST する例です。
$ curl -X POST -H "Content-Type: application/json" -d '{"key":"value"}' https://httpbin.org/post
{
"args": {},
"data": "{\"key\":\"value\"}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "15",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-65bb4d95-1fb42a532d8bdd4e3c5a989a"
},
"json": {
"key": "value"
},
"origin": "192.168.1.1",
"url": "https://httpbin.org/post"
}
-x (--proxy)
プロキシサーバーを経由してアクセスしたい場合に使います。プロキシサーバーがユーザー名とパスワード認証を必要とする場合は--proxy-user オプションを追加します。
$ curl -x http://localhost:8888 http://example.com
<!doctype html>
<html>
<head>
<title>Example Domain</title>
<meta charset="utf-8" />
<meta http-equiv="Content-type" content="text/html; charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<style type="text/css">
body {
background-color: #f0f0f2;
margin: 0;
padding: 0;
font-family: -apple-system, system-ui, BlinkMacSystemFont, "Segoe UI", "Open Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
}
div {
width: 600px;
margin: 5em auto;
padding: 2em;
background-color: #fdfdff;
border-radius: 0.5em;
box-shadow: 2px 3px 7px 2px rgba(0,0,0,0.02);
}
a:link, a:visited {
color: #38488f;
text-decoration: none;
}
@media (max-width: 700px) {
div {
margin: 0 auto;
width: auto;
}
}
</style>
</head>
<body>
<div>
<h1>Example Domain</h1>
<p>This domain is for use in illustrative examples in documents. You may use this
domain in literature without prior coordination or asking for permission.</p>
<p><a href="https://www.iana.org/domains/example">More information...</a></p>
</div>
</body>
</html>
なお、上記はローカル(のdocker のtinyproxy)でデプロイしていますが、通常は環境によってこのプロキシサーバーを使ってください、などのルールがあるはずです。その際にはcurl を実行するたびにurl を指定するのは面倒なので、環境変数を設定することもできます。詳細は下記を参照してください。
https://everything.curl.dev/usingcurl/proxies/env
-v (--verbose)
リクエストヘッダー、使用される HTTP メソッドなど、送信されたリクエストに関する詳細な情報を出力します。主にデバッグの際に有用です。
$ curl -v -X POST https://httpbin.org/post -d "param1=value1¶m2=value2"
Note: Unnecessary use of -X or --request, POST is already inferred.
* Trying 3.224.224.8:443...
* TCP_NODELAY set
* Connected to httpbin.org (3.224.224.8) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
* CAfile: /etc/ssl/certs/ca-certificates.crt
CApath: /etc/ssl/certs
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
* subject: CN=httpbin.org
* start date: Sep 21 00:00:00 2023 GMT
* expire date: Oct 18 23:59:59 2024 GMT
* subjectAltName: host "httpbin.org" matched cert's "httpbin.org"
* issuer: C=US; O=Amazon; CN=Amazon RSA 2048 M02
* SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x557300743630)
> POST /post HTTP/2
> Host: httpbin.org
> user-agent: curl/7.68.0
> accept: */*
> content-length: 27
> content-type: application/x-www-form-urlencoded
>
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* We are completely uploaded and fine
< HTTP/2 200
< date: Thu, 01 Feb 2024 08:09:21 GMT
< content-type: application/json
< content-length: 458
< server: gunicorn/19.9.0
< access-control-allow-origin: *
< access-control-allow-credentials: true
<
{
"args": {},
"data": "",
"files": {},
"form": {
"param1": "value1",
"param2": "value2"
},
"headers": {
"Accept": "*/*",
"Content-Length": "27",
"Content-Type": "application/x-www-form-urlencoded",
"Host": "httpbin.org",
"User-Agent": "curl/7.68.0",
"X-Amzn-Trace-Id": "Root=1-65bb51b1-5cc79caf1a6f9668318b413b"
},
"json": null,
"origin": "192.168.1.1",
"url": "https://httpbin.org/post"
}
* Connection #0 to host httpbin.org left intact
これら以外にもたくさんのオプションがありますが、使う頻度が少ないものも多いので、まずはこれだけ理解しておけば十分だと思います。
Windows で実行する場合の注意点
上記はすべてLinux (Ubuntu)で実施していますが、Windows でcurl を実行する場合に引っかかるポイントが主に2つあります。1つはPowershell で実行する場合に、curl は厳密にはcurl ではなく、Invoke-WebRequest のエイリアスになります。
> Get-Alias curl
CommandType Name Version Source
----------- ---- ------- ------
Alias curl -> Invoke-WebRequest
Powershell でcurl を実行したい場合は、curl.exe を実行してください。
> curl.exe -h
Usage: curl [options...] <url>
-d, --data <data> HTTP POST data
-f, --fail Fail fast with no output on HTTP errors
-h, --help <category> Get help for commands
-i, --include Include protocol response headers in the output
-o, --output <file> Write to file instead of stdout
-O, --remote-name Write output to a file named as the remote file
-s, --silent Silent mode
-T, --upload-file <file> Transfer local FILE to destination
-u, --user <user:password> Server user and password
-A, --user-agent <name> Send User-Agent <name> to server
-v, --verbose Make the operation more talkative
-V, --version Show version number and quit
This is not the full help, this menu is stripped into categories.
Use "--help category" to get an overview of all categories.
For all options use the manual or "--help all".
もう1つPowershell で実行する場合の注意点として、特殊文字の扱い方の違いから、コマンドの記述方法が異なる場合があります。特にJSON の送信の際は注意が必要です。例えばダブルクォートの中でダブルクォートをそのまま使えないため、シングルクォートでダブルクォートを含む文字を囲むようにします(またはエスケープ文字を使うこともできますが、その場合はダブルクォートの数が増えるので個人的には可読性の観点からお勧めしません)。
> curl -X POST -H "Content-Type: application/json" -d "{"key":"value"}" https://httpbin.org/post
Invoke-WebRequest : パラメーター 'Headers' をバインドできません。"Content-Type: application/json" の値
を "System.String" 型から "System.Collections.IDictionary" 型に変換できません。
発生場所 行:1 文字:17
+ curl -X POST -H "Content-Type: application/json" -d "{"key":"value"}" ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidArgument: (:) [Invoke-WebRequest]、ParameterBindingException
+ FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.InvokeWebR
equestCommand
ダブルクォートの中でダブルクォートを使った場合は型エラーが出ますが、下記のようにシングルクォートで囲んだ場合は問題なくcurl が実行できます。
> curl.exe -X POST -H "Content-Type: application/json" -d '{"key":"value"}' https://httpbin.org/post
{
"args": {},
"data": "{key:value}",
"files": {},
"form": {},
"headers": {
"Accept": "*/*",
"Content-Length": "11",
"Content-Type": "application/json",
"Host": "httpbin.org",
"User-Agent": "curl/8.4.0",
"X-Amzn-Trace-Id": "Root=1-65bb4fdc-446bb0686d9716e3233b9f82"
},
"json": null,
"origin": "192.168.1.2",
"url": "https://httpbin.org/post"
}
まとめ
本記事ではcurl の基本的な使い方をユースケースとともに紹介しました。curl にはオプションがたくさんありますが、実際あまり使うこともないオプションも多いため、本記事で紹介した内容を理解しつつ、必要になったら他のコマンドを調べてみる、というスタンスで十分だと思います。