curlコマンドでちょこっとHTTPリクエストを試すだけの記事


はじめに

こんにちは!お久しぶりです。
「実行されるとアプリサーバーにJSONを送るだけのバッチ」を作りたい人です1

先輩に実装方法を聞いたら「そんなんcurl一択やんけ」と言われたので、curlコマンドを調べて使ってバッチを作成しました!

その時に得た知識をまとめていきたいと思います。

この記事では、以下の順番でcurlの基礎をご紹介していきます。

  • curlコマンドって何?
  • curlの基本の使い方
  • どんな動作するのか、さくっと試したい!(試せますぞ!)
  • curlの後ろにオプションをつけると、いろいろなことができますぞ!

curlコマンドって何?

curlコマンドは、こちらの記事で紹介されているように、様々なプロトコルを使用してデータ転送を行うことができるコマンドです。

HTTPのGETやPOSTはもちろん、HTTPSやFTP, Telnet, SMTP, IMAP, POP3など様々な通信プロトコルをサポートしています。

最近の端末には最初から入っていて、ターミナルですぐにcurlコマンドを使用できる状態だと思いますが、入っていない場合はインストールが必要です

当記事での環境とバージョン

macOS Catalina
curl 7.64.1

$ curl --version
curl 7.64.1 (x86_64-apple-darwin19.0) libcurl/7.64.1 (SecureTransport) LibreSSL/2.8.3 zlib/1.2.11 nghttp2/1.39.2
Release-Date: 2019-03-27
Protocols: dict file ftp ftps gopher http https imap imaps ldap ldaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp 
Features: AsynchDNS GSS-API HTTP2 HTTPS-proxy IPv6 Kerberos Largefile libz MultiSSL NTLM NTLM_WB SPNEGO SSL UnixSockets

バージョン情報を聞いただけでサポートしてるプロトコルとバージョンの特色も表示してくれるの、優しいですね!

今回はプロトコルの中でもHTTP通信のみ使用していきます!

curlの基本の使い方

curlコマンドの基本形は下記の通りです。

$ curl {URL}

これで、URLのコンテンツをコンソールに表示させることができます。

試しにGoogleをcurlしてみましょう。

$ curl https://www.google.com/

<!doctype html><html itemscope="" itemtype="http://schema.org/WebPage" lang="ja"><head><meta content="&#19990;…
…中略…
…google.pmc=JSON.parse(pmc);})();</script></body></html>

Googleをcurlで取得すると、このようにひどく長いHTMLが取得できると思います。

Googleのレスポンス、長いし意味分かんないよ!ピンと来ないよ!という方は、阿部寛さんのホームページを参考にしてみてはいかがでしょうか?

$ curl http://abehiroshi.la.coocan.jp/

<html>
<head>
…中略…
<title>阿部寛のホームページ</title>
</head>
  …中略…
  <body></body>
  …中略…
</html>

上述のようなシンプルで美しいHTMLが返ってこれば、上手く行っています!
(titleが文字化けしていても、通信自体はうまく行っているので大丈夫です!阿部寛さんのホームページでF12/option+command+Iを押してみて、内容を見比べてみてください!)

もし下記のようなメッセージが出てくる場合、curlがデフォルトで入っていない可能性があるので、インストールを試してみてください

zsh: command not found: curl

どんな動作するのか、さくっと試したい!(試せますぞ!)

さて、これからcurlコマンドを書いていくのですが、実際にアプリサーバと疎通した時にどういう返事が返ってくるのか、気になりませんか?

さくっと試してみるだけなら、Googleとか有名なサイトを少し見てみれば良いのですが、

「エラーが出たときはどんなものが返ってくるのか?」
「GETばかりしているけれど本当はPOSTしたいんだよね…2

こういう時に、いつまでもまるっと阿部さんに頼りきりではいけませんよね…

そんな時にはhttpbinがおすすめです!

こちらは、HTTPリクエストをすると、いろいろなレスポンスを返してくれるWebサイトです。リクエストの書き方が正しいか、きちんとHTTP通信を行えるものなのかをさらりと確認できます!

また、URLを少し変えるだけで、GETやPOSTをそれぞれ行えたり、終了コードを恣意的に400や500にしたりすることもできます。curlに限らず、HTTP/HTTPS通信するコードだけぬるっと試してみたい時におすすめのWebサービスです。

この記事でも、しれっとhttpbinを使用していきます〜

curlの後ろにオプションをつけると、いろいろなことができますぞ!

さて、今まではシンプル・オーソドックス・ビューティフルかつピュアなcurlコマンドで遊んできましたが、実はcurlの後ろにはオプションを設定することができます!

これによってGETやPOSTを使い分けたり、ヘッダーやボディー、レスポンスを詳細に設定したり、エラーメッセージを表示させなかったりと、様々な詳細設定が可能となるのです。

【メソッド変更】curl -X {リクエストメソッド} “URL”

まずは、最もシンプルなリクエストメソッドの変更を試してみましょう。

Googleの例のように、何もオプションをつけないとGETメソッドとなりますが、明示的にリクエストメソッドを指定したい場合は-X {リクエストメソッド} “URL”で変更することができます。

##########
# GETメソッド
# (curl http://httpbin.org/getと同じ結果になる)
##########

$ curl -X GET "http://httpbin.org/get"

{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.64.1", 
    "X-Amzn-Trace-Id": "Root=12345678901234567890"
  }, 
  "origin": "xxx.xxx.xxx.xxx", 
  "url": "http://httpbin.org/get"
}

こちらはPOSTメソッドの例3です。

##########
# POSTメソッド
##########

$ curl -X POST "http://httpbin.org/post" 

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.64.1", 
    "X-Amzn-Trace-Id": "Root=12345678901234567890"
  }, 
  "json": null, 
  "origin": "xxx.xxx.xxx.xxx", 
  "url": "http://httpbin.org/post"
}

【ヘッダ変更】curl -H “{パラメータ}”: “{値}”

-H “{パラメータ}”: “{値}” をつけることで、HTTPヘッダを追加することができます。
(ここからはPOSTメソッドで試していきます!)

$ curl -X POST "http://httpbin.org/post" -H "accept: application/json"

{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.64.1", 
    "X-Amzn-Trace-Id": "Root=12345678901234567890"
  }, 
  "json": null, 
  "origin": "xxx.xxx.xxx.xxx", 
  "url": "http://httpbin.org/post"
}

いかがでしょうか?

さっきのものとじっくり比べると、 “headers”内の “Accept”項目が変化しているのが分かりますね!

先ほどの-Xのみの例では "Accept": "/" だったのに対し、今回の-X -Hでは Accept": "application/json" となっています!

【コンテンツ変更】curl -X POST -d ‘{“パラメータ”}: {“値”}’

今度はいよいよPOSTメソッドでJSONを送ってみます!

HTTPヘッダに"content-type: application/json"を追加し、POSTメソッドに-dオプションを付与することで、POSTメソッドでJSON形式のデータをリクエストすることができます。

$ curl -H "content-type: application/json" -X POST -d'{"asa_gohan":"misosiru", "oyatsu":"karl"}' http://httpbin.org/post

{
  "args": {}, 
  "data": "{\"asa_gohan\":\"misosiru\", \"oyatsu\":\"karl\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "41", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.64.1", 
    "X-Amzn-Trace-Id": "Root=12345678901234567890"
  }, 
  "json": {
    "asa_gohan": "misosiru", 
    "oyatsu": "karl"
  }, 
  "origin": "xxx.xxx.xxx.xxx", 
  "url": "http://httpbin.org/post"
}

朝ご飯といえば味噌汁、おやつといえばkarlですよね!

【通信詳細出力】curl -v

-vオプションHTTP通信の詳細を出力するためのオプションです。

リクエストヘッダ、レスポンスヘッダとボディが見れるので、デバッグする時に付与すると便利です。

$ curl -v -H "content-type: application/json" -X POST -d'{"asa_gohan":"misosiru", "oyatsu":"karl"}' http://httpbin.org/post

*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to httpbin.org (xxx.xxx.xxx.xxx) port xx (xx)
> POST /post HTTP/1.1
> Host: httpbin.org
> User-Agent: curl/7.64.1
> Accept: */*
> content-type: application/json
> Content-Length: 41
> 
* upload completely sent off: 41 out of 41 bytes
< HTTP/1.1 200 OK
< Date: Mon, 30 Mar 2020 xx:xx:xx GMT
< Content-Type: application/json
< Content-Length: 486
< Connection: keep-alive
< Server: xxxxxxxx/xxxxxxxx
< Access-Control-Allow-Origin: *
< Access-Control-Allow-Credentials: true
< 
{
  "args": {}, 
  "data": "{\"asa_gohan\":\"misosiru\", \"oyatsu\":\"karl\"}", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept": "*/*", 
    "Content-Length": "41", 
    "Content-Type": "application/json", 
    "Host": "httpbin.org", 
    "User-Agent": "curl/7.64.1", 
    "X-Amzn-Trace-Id": "Root=12345678901234567890"
  }, 
  "json": {
    "asa_gohan": "misosiru", 
    "oyatsu": "karl"
  }, 
  "origin": "xxx.xxx.xxx.xxx", 
  "url": "http://httpbin.org/post"
}
* Connection #0 to host httpbin.org left intact
* Closing connection 0

この最後の行の0は、Linuxコマンドの終了コードです。

Linuxコマンドは正常終了時は0、異常終了時は1~255の正の整数が返ってくるものなのですが、curlはHTTP通信時に400系エラーや500系エラーなどが出ても、終了コードが0になってしまいます。

あたかも成功したかのような顔をするタイプのコマンドです。いけすかないですね。

【終了コード変更】curl -f

エラーになってもしれっと正常終了する、ミス隠蔽マンcurlくんですが、-fオプションを付ければ、異常終了時に終了コード22で終わってくれます!やったー!

httpbinのStatus codesを使用します。

まずは-fオプションなしのエラー

##########
# 400
##########
$ curl -X POST "http://httpbin.org/status/400" -H "accept: text/plain"

# 何も出ない…成功したの?失敗したの?(本当は400エラーで失敗している)
# echo $?コマンドで、直前に実行したコマンドの終了コードを表示できます。

$ echo $?
0

ほら…すぐ嘘つくんだから…

しかし、-fを付与してあげると、きちんとエラーを吐いてくれます!

##########
# 400
##########
$ curl -f -X POST "http://httpbin.org/status/400" -H "accept: text/plain"
curl: (22) The requested URL returned error: 400 BAD REQUEST

# やったー!分かりやすい!
# echo $?コマンドで一応確認しておきます。

$ echo $?
22

ヤッターーーー!!!!

404でも500でも、curlのエラーコードとHTTPエラーコードが表示されるので、とっても分かりやすいです!

$ curl -f -X POST "http://httpbin.org/status/404" -H "accept: text/plain"                                                       
curl: (22) The requested URL returned error: 404 NOT FOUND


$ curl -f -X POST "http://httpbin.org/status/500" -H "accept: text/plain"
curl: (22) The requested URL returned error: 500 INTERNAL SERVER ERROR

ただ、curl -fのみではフェールセーフではなく、401や407エラーなど認証系エラーが無視される可能性があるという公式ドキュメントの記述もあります。

そのためcurl -sSを追加してエラー時のみエラーメッセージを表示する方法もあるそうです!

おわりに

curl難しい…!特に終了コードの概念はなかったので、新しいことだらけでびっくりしてました!

また、誤認等ございましたら、そっと教えていただけますと幸いです…!>< よろしくお願いいたします。

ちなみに「実行されるとアプリサーバーにJSONを送るだけのバッチ」は無事に完成したので、前回の記事でご紹介いただいたラーメン屋さんで一杯やろうかと思います!

いっぱいコメントありがとうございました!5億杯食べてきますね〜


  1. 当記事は下記記事の続きですが、「Linuxとかシェルって何?」を知っていればこの記事からでも読めます!【黒い画面恐怖症向け】Linuxとかシェルとかざっくり知りたいのでゆるく図解した 

  2. GETとPOSTの違いはこちらのQiita記事が分かりやすいです! 

  3. httpbinでは、デバッグ等に便利なようレスポンスにorigin等出してくれちゃうのですが、個人情報もあるため記事では伏せています!