curlコマンドでPOSTリクエストのボディを送信する方法

はい、承知いたしました。curlコマンドを使用してPOSTリクエストのボディを送信する方法について、詳細な説明を含む記事を作成します。約5000語を目指して記述します。


curlコマンドでPOSTリクエストのボディを送信する方法:完全ガイド

はじめに

今日のWeb開発やシステム間連携において、HTTPプロトコルは不可欠な基盤です。特に、クライアントからサーバーへデータを送信する場合、HTTPのPOSTメソッドが広く利用されます。RESTful APIへのデータ送信、Webフォームの送信、ファイルのアップロードなど、その用途は多岐にわたります。

コマンドラインツールである curl は、HTTPリクエストを送信するための非常に強力で柔軟性の高いツールです。開発者、システム管理者、APIテスターなど、多くのプロフェッショナルにとって手放せないツールとなっています。特にPOSTリクエストでサーバーにデータを渡す際には、リクエストボディに適切なデータを格納して送信する必要があります。

本記事では、curl コマンドを使用してPOSTリクエストのボディを送信する様々な方法について、詳細かつ網羅的に解説します。単にコマンドの書き方を示すだけでなく、それぞれの方法がどのように機能するのか、どのような場合に適しているのか、そして遭遇しうる問題とその解決策についても深く掘り下げます。約5000語というボリュームで、curl を使ったPOSTリクエストボディ送信に関するあらゆる疑問に答えられるような内容を目指します。

この記事を読むことで、あなたは以下のことができるようになります。

  • 基本的なキー/値ペアのデータをPOSTする。
  • JSON形式のデータをAPIに送信する。
  • ファイルの内容をリクエストボディとして送信する。
  • HTMLフォームと同様に、multipart/form-data 形式でデータを送信したり、ファイルをアップロードしたりする。
  • リクエストヘッダー、特に Content-Type の重要性を理解し、適切に設定する。
  • POSTリクエストに関連するよくある問題(引用符、エンコーディングなど)を解決する。
  • curl の詳細出力を見て、リクエストとレスポンスの情報を確認する。

それでは、curl でPOSTリクエストのボディを送信する世界へ踏み込みましょう。

1. HTTP POSTメソッドとリクエストボディの基本

HTTP/1.1仕様において、POSTメソッドは、指定されたリソースに対してデータを送信するために使用されます。PUTメソッドが「リソースの作成または更新」を意図するのに対し、POSTメソッドはより広範な意味合いを持ちます。一般的には「指定されたリソース(例えば、コレクションを表現するURI)に新しいエンティティを追加する」「データブロックを処理する(例えば、フォームデータの送信、検索クエリの送信)」「既存リソースに変更を適用する」といった用途で使われます。

POSTリクエストの重要な特徴の一つは、送信するデータをリクエストボディに含めることができる点です。GETリクエストではデータをURLのクエリパラメータとして渡すのが一般的ですが、POSTリクエストではボディに任意の形式のデータを格納できます。これにより、大量のデータを送信したり、URLに含めるのが不適切な機密性の高いデータやバイナリデータを送信したりすることが可能になります。

リクエストボディに含まれるデータの形式は任意ですが、サーバーがそのデータを正しく解釈できるように、クライアントは通常、リクエストヘッダーの Content-Type フィールドでボディのデータ形式を指定します。例えば、プレーンテキスト、フォームデータ、JSON、XML、バイナリデータなど、様々なMIMEタイプが Content-Type として使用されます。

curl コマンドは、このPOSTリクエストのリクエストボディを構築し、送信するための様々なオプションを提供します。これらのオプションを理解し、使い分けることが、効果的なPOSTリクエストの送信には不可欠です。

2. 基本的なPOSTリクエストの送信 (-X POST)

curl はデフォルトでGETリクエストを送信しますが、-X または --request オプションを使用することで、他のHTTPメソッドを指定できます。POSTリクエストを送信する場合、通常は以下のように指定します。

bash
curl -X POST [URL]

しかし、これだけではリクエストボディは空です。POSTリクエストの目的の多くはデータを送信することですから、次にボディを付加する方法を見ていきましょう。

3. リクエストボディの送信方法(最も一般的: -d / --data

curl でリクエストボディを送信する最も一般的で簡単な方法は、-d または --data オプションを使用することです。このオプションは、指定したデータをリクエストボディとして含め、さらに特別な挙動をいくつか持ちます。

3.1. -d オプションの基本的な使い方

-d オプションの後に送信したいデータを文字列として指定します。

bash
curl -X POST -d 'key1=value1&key2=value2' http://example.com/api/submit

このコマンドは、http://example.com/api/submit に対してPOSTリクエストを送信します。リクエストボディは 'key1=value1&key2=value2' となります。

-d オプションを使用すると、curl は以下の2つのことを自動的に行います。

  1. リクエストメソッドをPOSTに変更します。したがって、上記のように -X POST を明示的に指定する必要はありません。-d を使うだけでPOSTリクエストになります。
  2. 特に Content-Type ヘッダーを指定しない場合、curl は自動的に Content-Type: application/x-www-form-urlencoded ヘッダーを追加します。これは、WebブラウザがHTMLフォームをPOST送信する際のデフォルトの形式です。

したがって、多くの場合、最もシンプルなPOSTリクエストは -X POST なしで -d を使うだけで十分です。

bash
curl -d 'key1=value1&key2=value2' http://example.com/api/submit

この形式は、GETリクエストのクエリパラメータのように、キーと値のペアを & で繋ぎ、各ペアを = で区切る形式(URLエンコーディングされたフォームデータ形式)でデータを送信するのに適しています。

3.2. -d オプション使用時のデータ形式とエンコーディング

-d オプションに渡されたデータは、デフォルトでは自動的にURLエンコードされます。これは、スペースや &= などの特殊文字がサーバー側で正しく解釈されるようにするためです。

例えば、データとして 'name=Test User&message=Hello World!' を送信したい場合、スペースが含まれています。

bash
curl -d 'name=Test User&message=Hello World!' http://example.com/api/submit

curl はこれを送信する際に、おそらく内部的に 'name=Test+User&message=Hello+World%21' のようにエンコードします(スペースは + または %20!%21 など)。

ただし、-d オプションの自動URLエンコーディングには注意が必要です。文字列全体をエンコードするのではなく、= の右側の値のみ、あるいは特定の文字のみをエンコードするなど、状況によって挙動が変わる可能性があります。より確実にURLエンコードを制御したい場合は、後述の --data-urlencode オプションを使うべきです。

3.3. JSONデータの送信 (-dContent-Type)

RESTful APIなどでは、リクエストボディにJSON形式のデータを格納して送信するのが一般的です。-d オプションは文字列データを送信するため、JSON文字列をそのまま渡すことができます。

bash
curl -d '{"name": "Test User", "age": 30}' http://example.com/api/users

しかし、この場合、curl はデフォルトで Content-Type: application/x-www-form-urlencoded をヘッダーに含めてしまいます。APIサーバーは通常、JSON形式のボディを期待しており、ヘッダーが application/json でない場合はボディを正しく解釈できない可能性があります。

したがって、JSONデータを送信する際は、必ず -H または --header オプションを使用して Content-Type: application/json ヘッダーを明示的に指定する必要があります。

bash
curl -X POST -H "Content-Type: application/json" -d '{"name": "Test User", "age": 30}' http://example.com/api/users

-X POST-d を使う場合は必須ではありませんが、明示することで意図がより明確になります。ここでは -X POST を含めた完全な形で示しています。

JSON文字列内の引用符とエスケープ:

JSONデータはキーと値をダブルクォート " " で囲みます。コマンドラインのシェルでは、シングルクォート ' ' またはダブルクォート " " を使って文字列を囲みます。

  • コマンドラインでシングルクォート ' ' を使う場合、JSON内のダブルクォートはそのまま記述できます。

    bash
    curl -H "Content-Type: application/json" -d '{"name": "Test User", "message": "Hello \"World\""}' http://example.com/api/message

    この例では、メッセージの中に " が含まれていますが、外側をシングルクォートで囲んでいるため、JSON内の \" はシェルによって解釈されず、そのままサーバーに送信されます。JSON形式では、文字列内のダブルクォートはバックスラッシュ \ でエスケープする必要があります。

  • コマンドラインでダブルクォート " " を使う場合、JSON内のダブルクォートはシェルの特別な意味を持つため、バックスラッシュ \ でエスケープする必要があります。

    bash
    curl -H "Content-Type: application/json" -d "{\"name\": \"Test User\", \"age\": 30}" http://example.com/api/users

    さらに、JSON文字列自体にバックスラッシュが含まれる場合(例えばファイルパスなど)、そのバックスラッシュもシェルのエスケープ文字と衝突しないように注意が必要です。一般的には、JSON文字列を扱う際はシングルクォートで囲む方が、JSON内のダブルクォートのエスケープをそのまま書けるため扱いやすいことが多いです。

複雑なJSONデータや、動的に生成されるJSONデータを扱う場合は、次に説明するファイルからの読み込みが便利です。

3.4. ファイルからのデータ読み込み (-d @filename)

-d オプションは、ファイルの内容をリクエストボディとして送信することもできます。その場合は、データの前に @ プレフィックスを付け、ファイルパスを指定します。

bash
curl -H "Content-Type: application/json" -d @data.json http://example.com/api/items

このコマンドは、data.json というファイルの内容を読み込み、それをリクエストボディとして送信します。ヘッダーで Content-Type: application/json を指定しているため、ファイルの内容がJSON形式であることをサーバーに伝えます。

ファイルからの読み込みは、以下のような場合に非常に便利です。

  • 送信するデータが長い、複雑なJSON、XMLなどである場合。
  • データが自動生成されたものである場合。
  • コマンドラインで直接入力するのが面倒な場合。

ファイルの内容はそのままリクエストボディとして送信されます。-d オプションの基本的な挙動(URLエンコーディングやデフォルトのContent-Type設定)は、ファイルからの読み込みの場合も適用されます。ただし、ファイルの内容がJSONであれば、通常は Content-Type: application/json を明示的に指定します。ファイルの内容が既にURLエンコードされたフォームデータであれば、Content-Typeの指定は不要です。

例えば、data.txt というファイルに key1=value1&key2=value%20two と書かれている場合、

bash
curl -d @data.txt http://example.com/api/submit

とすると、ファイルの内容がそのままボディとして送信され、デフォルトで Content-Type: application/x-www-form-urlencoded が付加されます。

注意: -d オプションの @ プレフィックスは、ファイルからの読み込みを指示する特別な記号です。もし送信したいデータ文字列が @ で始まる場合、curl はそれをファイルパスと誤解釈してしまいます。このような場合は、後述の --data-raw オプションを使用する必要があります。

3.5. 複数の -d オプション

curl コマンドラインで -d オプションを複数回指定することができます。この場合、curl は指定された全てのデータを結合し、間に & を挿入して一つのリクエストボディとして送信します。

bash
curl -d 'key1=value1' -d 'key2=value2' http://example.com/api/submit

これは、-d 'key1=value1&key2=value2' とほぼ同じ結果になります。データの間に自動的に & が挿入されるため、application/x-www-form-urlencoded 形式のデータを少しずつ追加していくのに便利かもしれません。

ただし、JSONなどの他の形式でデータを送信する場合には、複数の -d オプションの使用は推奨されません。通常は一つの -d オプションで完全なJSON文字列を指定するか、ファイルから読み込む方が明確です。

4. -d の亜種オプションの詳細な使い方

-d オプションは非常に便利ですが、特定のシナリオではその挙動をより細かく制御したい場合があります。そのために、curl はいくつかの亜種オプションを提供しています。

4.1. --data-raw オプション

--data-raw オプションは、-d と非常によく似ていますが、唯一かつ重要な違いは、データの先頭にある @ を特別扱いしないことです。その他の点(デフォルトでPOSTメソッドになる、Content-Typeが指定されていなければ application/x-www-form-urlencoded を追加するなど)は -d と同じです。

このオプションは、送信したいデータが @ という文字で偶然始まる場合に、curl がそれをファイルパスと誤解釈するのを防ぐために使用します。

“`bash

送信したいデータが ‘@username’ という文字列の場合

-d ではファイルとして解釈されてしまう可能性がある

curl -d ‘@username’ http://example.com/api/handle

–data-raw を使えば文字列として送信される

curl –data-raw ‘@username’ http://example.com/api/handle
“`

また、--data-raw は、-d によるデフォルトのURLエンコーディングを行いません(あるいは、非常に限定的なエンコーディングのみを行います)。生のデータをそのままボディとして送信したい場合に --data-raw を使用することができます。ただし、通常、生のデータを送信する場合は、後述の --data-binary や他の方法が使われます。--data-raw の主な用途は、-d@ の特別扱いを回避することにあると言えます。

JSONデータを送信する際に --data-raw を使うことも可能です。

bash
curl -H "Content-Type: application/json" --data-raw '{"name": "Test User", "age": 30}' http://example.com/api/users

この場合、-d と同様にJSON文字列が送信されます。ファイルから読み込む場合も @filename の形式は --data-raw でも有効ですが、前述の通り @ の特別扱いはされません。つまり、--data-raw @data.json はファイルの内容を読み込みますが、データ自体が @ で始まっていてもファイルとして解釈されることはありません(ただし、ファイル名として扱われる可能性はあります)。紛らわしさを避けるため、ファイルから読み込む場合は -d @filename を、生の文字列をそのまま送信したい場合は --data-raw '...' を使うのが一般的でしょう。

4.2. --data-urlencode オプション

--data-urlencode オプションは、指定したデータをURLエンコードしてからリクエストボディとして送信します。これも -d と同様にデフォルトでPOSTメソッドを使用し、Content-Type: application/x-www-form-urlencoded を設定します。

このオプションの利点は、エンコードしたい部分を明確に指定できることです。特に、キーと値を別々にエンコードしてから結合したい場合や、複雑な文字列を確実にエンコードしたい場合に役立ちます。

基本的な使い方は以下の通りです。

bash
curl --data-urlencode 'key=value with spaces & symbols!' http://example.com/api/submit

curl'key=value with spaces & symbols!' という文字列全体をURLエンコードし、key=value+with+spaces+%26+symbols%21 のように変換してからリクエストボディとして送信します。

key=value 形式で指定しない場合、例えば単に --data-urlencode 'some data with spaces' のように指定した場合、curl はそれをそのままエンコードしてボディとします。

さらに、このオプションは @filename< filename のプレフィックスもサポートしており、ファイルから読み込んだ内容をURLエンコードして送信できます。

“`bash

data.txt ファイルの内容をURLエンコードして送信

curl –data-urlencode @data.txt http://example.com/api/submit

標準入力から読み込んだ内容をURLエンコードして送信

echo ‘data from stdin with spaces’ | curl –data-urlencode @- http://example.com/api/submit
``
@-` は標準入力を意味します)

複数の --data-urlencode オプションを指定することも可能です。この場合、-d と同様に各オプションで指定されたエンコード済みのデータが & で結合されます。

“`bash
curl –data-urlencode ‘key1=value 1’ –data-urlencode ‘key2=value 2’ http://example.com/api/submit

結果として送信されるボディ: key1=value+1&key2=value+2

“`

このオプションは、特に application/x-www-form-urlencoded 形式でデータを送信する際に、データのエンコーディングを確実に制御したい場合に非常に有効です。

4.3. --data-binary オプション

--data-binary オプションは、指定されたデータを一切加工せず、バイナリとしてリクエストボディに含めて送信します。これもデフォルトでPOSTメソッドを使用しますが、-d--data-urlencode とは異なり、デフォルトの Content-Type ヘッダーを追加しません。送信するデータの適切な Content-Type (例: application/octet-streamimage/jpeg など)を必ず明示的に指定する必要があります。

このオプションは、画像ファイル、音声ファイル、ZIPアーカイブなどのバイナリデータをそのまま送信したい場合に最適です。

基本的な使い方は、ファイルパスを @ プレフィックス付きで指定するのが一般的です。

bash
curl -X POST -H "Content-Type: application/octet-stream" --data-binary @image.jpg http://example.com/api/upload

このコマンドは、image.jpg ファイルの内容をバイナリデータとして読み込み、リクエストボディに含めて http://example.com/api/upload に送信します。Content-Type: application/octet-stream は「任意のバイナリデータ」を示す汎用的なMIMEタイプです。送信するデータの種類に応じて、より具体的なMIMEタイプ(例: image/jpeg)を指定する方が良いでしょう。

ファイルだけでなく、文字列をバイナリデータとして送信することも可能ですが、これは一般的ではありません。文字列を指定した場合も、--data-binary はその文字列をエンコードせず、そのままのバイト列として送信します。

“`bash

JSON文字列をエンコードせずそのまま送信したい場合(Content-Typeは別途指定)

curl -H “Content-Type: application/json” –data-binary ‘{“key”: “value”}’ http://example.com/api/data
``
この例は、JSON送信に
–data-rawを使うのと似ていますが、–data-binaryはContent-Typeを自動追加しない点で異なります。JSONの場合は通常–data-raw-d(ファイルから) を使うことが多いでしょう。–data-binary` は主に非テキストデータに使われます。

標準入力からの読み込み (@-) もサポートしています。

“`bash

標準入力から受け取ったバイナリデータをそのまま送信

cat binary_data.bin | curl -X POST -H “Content-Type: application/octet-stream” –data-binary @- http://example.com/api/upload
“`

--data-binary は、特にファイルアップロードAPIなどで、ファイルの中身をそのままリクエストボディとして送信する必要がある場合に強力なオプションです。

5. ファイルアップロードとフォーム送信 (-F / --form)

WebブラウザでHTMLフォームを使用する場合、enctype 属性に multipart/form-data を指定することで、複数のフィールド(テキストデータやファイル)をまとめてPOST送信できます。curl-F または --form オプションは、この multipart/form-data 形式のリクエストボディを構築し、送信するために使用されます。

multipart/form-data は、リクエストボディを複数の「パート」に分割し、各パートがフォームの1つのフィールドを表す形式です。各パートは独自のヘッダー(例えば、フィールド名を示す Content-Disposition や、パートのデータ形式を示す Content-Type)を持ちます。リクエストボディ全体は、自動生成される境界文字列(boundary string)で区切られます。

-F オプションは、キー/値ペアのデータ送信とファイルアップロードの両方に使用できます。-F オプションを使用すると、curl は自動的に以下のことを行います。

  1. リクエストメソッドをPOSTに変更します。
  2. Content-Type: multipart/form-data ヘッダーと、自動生成された境界文字列を追加します。

5.1. キー/値ペアの送信 (-F 'name=value')

-F オプションを使って、通常のフォームフィールドのようなキー/値ペアを送信できます。

bash
curl -F 'username=testuser' -F 'password=mypass' http://example.com/api/login

これは、リクエストボディに以下のような形式のデータを作成して送信します(境界文字列は実際にはランダムな文字列になります)。

“`
Content-Type: multipart/form-data; boundary=————————abcdef1234567890

————————–abcdef1234567890
Content-Disposition: form-data; name=”username”

testuser
————————–abcdef1234567890
Content-Disposition: form-data; name=”password”

mypass
————————–abcdef1234567890–
“`

複数の -F オプションを指定することで、複数のフィールドを送信できます。

5.2. ファイルアップロード (-F 'name=@/path/to/file')

-F オプションの最も強力な用途の一つは、ファイルのアップロードです。ファイルの内容をリクエストボディの特定のパートに含めるには、フィールド名の後に @ プレフィックスを付けてファイルパスを指定します。

bash
curl -F 'profile_image=@/path/to/your/image.jpg' http://example.com/api/upload_avatar

このコマンドは、/path/to/your/image.jpg というファイルを読み込み、profile_image というフィールド名で送信します。curl はファイルの内容をボディのパートとして含め、適切なヘッダーを自動的に追加します。

例えば、ファイルの内容が画像であれば、curl は自動的に Content-Type: image/jpeg のようなヘッダーをパートに追加しようと試みます。また、Content-Disposition ヘッダーには、元のファイル名 (image.jpg) も含められます。

生成されるリクエストボディの例:

“`
Content-Type: multipart/form-data; boundary=————————abcdef1234567890

————————–abcdef1234567890
Content-Disposition: form-data; name=”profile_image”; filename=”image.jpg”
Content-Type: image/jpeg # curlが自動的に判断しようとする

… (ファイルの内容) …
————————–abcdef1234567890–
“`

複数のファイルをアップロードする:

複数のファイルをアップロードしたい場合も、-F オプションを複数回指定するだけです。

bash
curl -F 'document1=@/path/to/doc1.pdf' -F 'document2=@/path/to/doc2.docx' http://example.com/api/upload_docs

ファイルフィールドにカスタムヘッダーを指定する:

ファイルアップロードのパートに、ファイル名や Content-Type などのヘッダーを明示的に指定したい場合があります。これは、-F 'name=@/path/to/file;filename=customname.txt;type=text/plain' のように、ファイルパスの後にセミコロン区切りで追加の情報を記述することで可能です。

“`bash

ファイル名を ‘report.txt’、Content-Type を ‘text/plain’ としてアップロード

curl -F ‘report=@/path/to/data.csv;filename=report.txt;type=text/plain’ http://example.com/api/upload
“`

filename= でサーバーに送信されるファイル名を指定できます。type= でパートの Content-Type ヘッダーを指定できます。これを指定しない場合、curl はファイル拡張子などから自動的に判断しようとしますが、明示的に指定する方が確実です。

5.3. 通常フィールドとファイルフィールドの組み合わせ

-F オプションは、通常のキー/値フィールドとファイルフィールドを組み合わせて使用できます。これは、Webフォームでテキスト入力とファイルアップロードを同時に行う場合と全く同じです。

bash
curl -F 'title=Quarterly Report' -F 'year=2023' -F 'report_file=@/path/to/report.pdf' http://example.com/api/submit_report

このコマンドは、titleyear というテキストフィールドの値、そして report_file というファイルフィールドとして /path/to/report.pdf を送信します。

5.4. @< プレフィックス

-F オプションでファイルの内容を指定する場合、@< の2つのプレフィックスを使用できます。

  • -F 'name=@/path/to/file': 指定したファイルを読み込み、その内容をパートのデータとして含めます。パートのヘッダーには、ファイル名 (/path/to/file のベース名) と、curl が判断した Content-Type が追加されます。
  • -F 'name=</path/to/file': 指定したファイルを読み込み、その内容をパートのデータとして含めます。しかし、@ を使った場合と異なり、パートのヘッダーにファイル名や Content-Type は追加されません。ファイルの内容を単にデータとして送りたいが、メタデータ(ファイル名、タイプ)は不要な場合に使われます。

例えば、単にテキストファイルの内容を特定のフィールドの値として送信したい場合は < が適しているかもしれません。

“`bash

text_content.txt の内容を ‘comment’ フィールドの値として送信

curl -F ‘comment=</path/to/text_content.txt’ http://example.com/api/add_comment
``
この場合、
text_content.txtの内容がcommentフィールドのデータとなりますが、パートにはfilenameContent-Type` ヘッダーは付加されません。

-F オプションは、Webブラウザのフォーム送信をシミュレートしたり、ファイルアップロードAPIをテストしたりする際に非常に強力で柔軟性の高い方法です。

6. 他のボディ送信方法(標準入力、パイプ、-T

ここまでに説明した -d-F は最もよく使われるオプションですが、curl は他にもリクエストボディを送信する方法を提供しています。

6.1. 標準入力またはパイプからのデータ読み込み

一部のオプション(-d--data-binary--data-urlencode)は、ファイルパスとして - を指定することで、標準入力からデータを読み込むことができます。これは、他のコマンドの出力を curl のPOSTリクエストのボディとして渡したい場合に便利です。

“`bash

echo コマンドの出力をPOSTボディとして送信 (application/x-www-form-urlencoded)

echo ‘status=online&message=hello’ | curl -d @- http://example.com/api/update

cat コマンドでファイル内容を読み込み、JSONとしてPOSTボディに送信

cat data.json | curl -H “Content-Type: application/json” -d @- http://example.com/api/items
“`

-d @- は、-d '<stdin>' の短縮形のようなものです。標準入力から読み込んだデータは、指定されたオプション(この場合は -d なのでURLエンコードやContent-Type自動設定)に従って処理されます。

これは、スクリプト内で動的に生成されたデータをPOSTしたい場合や、パイプライン処理の一部として curl を使いたい場合に非常に有効です。

6.2. -T / --upload-file オプション

-T または --upload-file オプションは、指定したファイルをサーバーにアップロードするために設計されたオプションです。通常、これはPUTメソッドと共に使用され、指定されたURLのリソースをファイルの内容で置き換えることを意図します。

しかし、特定のサーバー設定では、POSTメソッドで -T オプションを使用してファイルをアップロードできる場合があります。この場合、ファイルの内容がリクエストボディとして送信されます。

“`bash

POSTメソッドでファイルをボディとして送信(サーバーが対応している場合)

curl -X POST -T /path/to/local/file.txt http://example.com/upload
“`

-T オプションは、ファイルの Content-Type を自動的に判断しようとします。また、デフォルトで Content-Length ヘッダーも設定します。

-T をPOSTで使うケースは -d @file--data-binary @file に比べて少ないですが、一部のAPIやサーバーはこのような形式を受け付ける場合があります。基本的には、ファイルアップロードには -F (multipart/form-data) か --data-binary を使うのがより一般的で推奨される方法です。

7. リクエストヘッダーの操作 (-H) と Content-Type の重要性

前述の各セクションで触れてきましたが、POSTリクエスト、特にボディ送信においては、リクエストヘッダー、中でも Content-Type ヘッダーが非常に重要です。

-H または --header オプションを使用すると、任意のリクエストヘッダーを指定または上書きできます。構文は -H "Header-Name: Header Value" です。複数のヘッダーを指定する場合は、-H オプションを複数回使用します。

bash
curl -H "Content-Type: application/json" -H "Authorization: Bearer your_token" -d '{"key": "value"}' http://example.com/api/data

7.1. Content-Type ヘッダー

Content-Type ヘッダーは、リクエストボディの形式をサーバーに伝えます。サーバーはこれを見て、ボディのデータをどのようにパース(解析)すれば良いかを判断します。Content-Type が間違っていると、サーバーはボディを正しく処理できず、エラー(例: 415 Unsupported Media Type)を返す可能性が高くなります。

POSTリクエストボディでよく使用される Content-Type のMIMEタイプを以下に示します。

  • application/x-www-form-urlencoded: キーと値のペアをURLエンコードして & で結合した形式。-d オプションのデフォルトです。
  • application/json: JSON形式のデータ。APIとの連携で最もよく使われます。-d または --data-raw でJSON文字列を指定し、-H "Content-Type: application/json" と組み合わせます。
  • multipart/form-data: 複数のパートからなるフォームデータ。ファイルアップロードや、複数の種類のデータをまとめて送る際に使われます。-F オプションを使うと自動的に設定されます。
  • text/plain: 単なるプレーンテキストデータ。
  • application/xml: XML形式のデータ。
  • application/octet-stream: 任意のバイナリデータ。特定のMIMEタイプが不明な場合や、汎用的なバイナリデータを送る場合に利用されます。--data-binary と組み合わせて使われることがあります。
  • 画像や音声、動画などの特定のMIMEタイプ(例: image/jpeg, audio/mpeg, video/mp4):ファイルアップロードなどで、データの正確なタイプを伝えたい場合に指定します。--data-binary-F (type=…) と組み合わせて使われます。

curl-d-F を使うとデフォルトの Content-Type を設定しますが、JSON送信時など、明示的に正しい Content-Type-H で指定することが非常に重要です。指定した -H ヘッダーは、curl が自動で設定しようとするデフォルト値を上書きします。

7.2. その他の重要なヘッダー

POSTリクエスト全体に関連して、Content-Type 以外にも重要なヘッダーがあります。

  • Content-Length: リクエストボディのバイト数を示します。curl は通常、ボディのサイズを計算して自動的にこのヘッダーを追加するので、手動で指定する必要はほとんどありません。
  • Authorization: サーバーが認証を要求する場合、認証情報(例: Bearerトークン、Basic認証情報など)をこのヘッダーに含めます。-H "Authorization: Bearer your_token" のように使います。Basic認証の場合は -u user:password オプションを使うこともできますが、より柔軟な認証スキームには -H が必要です。
  • Accept: クライアントがサーバーからの応答として受け入れ可能なメディアタイプを指定します。これはリクエストボディとは直接関係ありませんが、APIとのやり取りにおいては重要なヘッダーです(例: -H "Accept: application/json")。
  • User-Agent: リクエストを送信しているクライアントの情報を伝えます。curl はデフォルトのUser-Agentを送信しますが、これをカスタマイズすることも可能です。

8. レスポンスの確認とデバッグ

リクエストを正しく送信できたか、サーバーがどのように応答したかを確認することは、開発やデバッグにおいて不可欠です。curl は様々なオプションでこれをサポートしています。

  • デフォルト: -o-O を指定しない場合、curl はサーバーからの応答ボディを標準出力に表示します。
  • -i / --include: 応答ヘッダーを含めて表示します。サーバーが返した Content-Type, Status Code などを確認できます。
  • -I / --head: HEADリクエストを送信し、応答ヘッダーのみを表示します。POSTリクエストのデバッグにはあまり使いませんが、参考までに。
  • -v / --verbose: リクエストとレスポンスの両方について、非常に詳細な情報を表示します。送信されたヘッダー、リクエストボディのデータ(一部)、接続情報、受信したヘッダーとボディなどが表示されます。POSTリクエストのボディがサーバーに意図通りに送信されたか確認するのに最も役立つオプションです。

例:JSONデータを送信し、詳細なやり取りを確認する

bash
curl -v -H "Content-Type: application/json" -d '{"name": "Test User"}' http://example.com/api/users

-v オプションの出力を見ると、以下のような情報が含まれます。

  • > で始まる行: curl が送信したリクエストヘッダー。ここで Content-Type が正しく設定されているか確認できます。
  • > の後に改行があり、その後に続くデータ: 送信されたリクエストボディ。-d で指定したデータがここに表示されます。
  • < で始まる行: サーバーが返した応答ヘッダー。Status Code(例: HTTP/1.1 200 OK400 Bad Request など)、応答の Content-Type などを確認できます。
  • < の後に改行があり、その後に続くデータ: サーバーが返した応答ボディ。APIからの結果データやエラーメッセージなどが表示されます。

-v オプションは、特にリクエストボディの送信に関する問題をデバッグする際に非常に強力なツールです。データが正しくフォーマットされているか、適切なヘッダーが付いているかなどを詳細に確認できます。

9. シェルと引用符、特殊文字の扱い

curl コマンドをシェル(Bash, Zshなど)で実行する際、コマンドライン引数として渡す文字列、特にリクエストボディのデータ文字列の扱いに注意が必要です。シェルは特定の文字(スペース, &, =, <, >, |, ", ', \ など)に特別な意味を持たせることがあります。

9.1. 引用符の使い分け

  • シングルクォート ('...'): シングルクォートで囲まれた文字列は、ほとんどの特殊文字($\ などを含む)がリテラル文字として扱われます。変数展開などは行われません。JSONデータのように内部にダブルクォートを含む文字列を渡す場合に適しています。JSON内のダブルクォートをエスケープする必要はありません。

    bash
    curl -H "Content-Type: application/json" -d '{"name": "Test User", "message": "Contains \"quotes\" and \\backslashes\\"}' http://example.com/api/data

    JSON文字列内の "\ はJSONのルールに従って \"\\ とエスケープされていますが、これらはシェルによって特別扱いされず、そのまま -d オプションの値として curl に渡されます。

  • ダブルクォート ("..."): ダブルクォートで囲まれた文字列では、$ (変数展開), ` (コマンド置換), \ (エスケープ) などの一部の特殊文字がシェルによって解釈されます。JSONデータのように内部にダブルクォートを含む文字列を渡す場合、JSON内のダブルクォートをシェルのルールに従ってバックスラッシュ \ でエスケープする必要があります。

    bash
    curl -H "Content-Type: application/json" -d "{\"name\": \"Test User\", \"message\": \"Contains \\\"quotes\\\" and \\\\backslashes\\\\\"}" http://example.com/api/data

    JSON内の "\" に、JSON内の \\\ になります。さらに、これらはダブルクォートで囲まれているため、シェルのルールとしてバックスラッシュ自体もエスケープが必要になり、最終的にJSON内の "\\" に、JSON内の \\\\\ と書く必要がある場合があります(シェルのバージョンや設定によりますが、通常は \"\\ で十分です)。このように二重にエスケープが必要になる可能性があるため、JSONをダブルクォートで囲むのは避けるのが無難です。

結論として、複雑な文字列やJSON文字列を -d--data-raw に渡す際は、シングルクォート '...' を使用し、その内部ではJSONやデータ形式自体のエスケープルールに従うのが、最も安全で推奨される方法です。

9.2. URLエンコーディングが必要な文字

application/x-www-form-urlencoded 形式でデータを送信する場合、スペース、&, =, ?, #, +, /, (日本語などの非ASCII文字) などの特定の文字はURLエンコードが必要です。

-d オプションはデフォルトで値をURLエンコードしますが、キー部分や、データ全体のエンコードをより制御したい場合は --data-urlencode を使用します。

例えば、key=value with spaces&symbols!? を送信したい場合:

“`bash

-d は通常、値部分をエンコード

curl -d ‘key=value with spaces&symbols!?’ http://example.com/api/submit

=> ボディ例: key=value+with+spaces%26symbols%21%3F

–data-urlencode は文字列全体をエンコード

curl –data-urlencode ‘key=value with spaces&symbols!?’ http://example.com/api/submit

=> ボディ例: key%3Dvalue%20with%20spaces%26symbols%21%3F

“`

-d--data-urlencode のエンコーディング挙動の違いを理解し、意図した形式でデータが送信されるように適切なオプションを選択することが重要です。

10. 高度な利用例と応用

curl のPOSTリクエストは、単にデータを送信するだけでなく、より高度なシナリオでも活用できます。

10.1. RESTful APIとの対話

RESTful APIの多くは、POSTメソッドを使って新しいリソースを作成します。通常、リクエストボディには作成するリソースのデータをJSON形式で含めます。

例:新しいユーザーを登録するAPIコール

bash
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer abcdef123456" \
-d '{"username": "newuser", "email": "[email protected]", "password": "securepassword"}' \
https://api.example.com/v1/users

このように、-X POST (または -d があれば省略可), -H (Content-Type や認証), -d (JSONボディ) を組み合わせてAPIと対話します。

10.2. トークン認証フローの一部として

一部のAPIでは、まず認証情報をPOSTしてアクセストークンを取得し、そのトークンを使って後続のAPIリクエスト(GET, POST, PUTなど)を行います。

例:認証トークンを取得し、それを使ってデータをPOSTする(シェルスクリプト内で)

“`bash

ステップ1: 認証情報をPOSTしてトークンを取得

応答はJSON形式で、”access_token” フィールドにトークンが含まれると仮定

AUTH_RESPONSE=$(curl -s -X POST \
-H “Content-Type: application/json” \
-d ‘{“client_id”: “…”, “client_secret”: “…”}’ \
https://auth.example.com/oauth/token)

jq コマンドなどを使ってJSONからトークンを抽出

(jqのインストールが必要)

ACCESS_TOKEN=$(echo $AUTH_RESPONSE | jq -r ‘.access_token’)

ステップ2: 取得したトークンを使ってデータをPOST

if [ -n “$ACCESS_TOKEN” ]; then
curl -X POST \
-H “Content-Type: application/json” \
-H “Authorization: Bearer $ACCESS_TOKEN” \
-d ‘{“item_name”: “New Item”, “price”: 100}’ \
https://api.example.com/v1/items
else
echo “Error: Failed to get access token.”
fi
``
この例では、シェル変数やサブコマンド置換 (
$()) を利用して、複数のcurlコマンドを連携させています。POSTリクエストの応答ボディをパースして必要な情報を取り出す処理(ここではjq` を使用)も、コマンドラインでのAPI操作ではよく行われます。

10.3. ファイルからのJSON読み込みと組み込み

複雑なJSONデータを送信する場合、コマンドラインに直接記述するのではなく、ファイルに保存して -d @filename で読み込む方が管理しやすくなります。

“`bash

request_body.json ファイルの内容をJSONボディとして送信

curl -X POST \
-H “Content-Type: application/json” \
-d @request_body.json \
http://example.com/api/complex_data
“`

request_body.json の内容は以下のようになっているとします。

json
{
"report": {
"title": "Sales Performance Q3",
"period": {
"start_date": "2023-07-01",
"end_date": "2023-09-30"
},
"metrics": [
{"name": "Revenue", "value": 123456.78},
{"name": "Profit", "value": 23456.78}
]
},
"options": {
"format": "pdf",
"delivery": "email"
}
}

このようにファイルを利用することで、コマンドラインが長くなりすぎるのを防ぎ、JSON構文エラーもエディタで確認しながら修正できます。

11. よくある問題とトラブルシューティング

curl でPOSTリクエストを送信する際に遭遇しやすい問題とその解決策をいくつか紹介します。

11.1. シェルによる特殊文字の解釈ミス

前述の通り、コマンドラインで -d--data-raw に渡す文字列がシェルによって誤って解釈されることがあります。

  • 問題: JSON文字列内の引用符や特殊文字が原因で構文エラーになる。
  • 解決策:
    • 文字列全体をシングルクォート ' ' で囲む。
    • JSONやデータ形式自体のエスケープルール(例: JSON内の "\")に従う。

11.2. Content-Type の不一致

サーバーが期待する Content-Type と、curl が送信する Content-Type が異なる場合、サーバーはボディを正しく処理できません。

  • 問題: JSONデータを送信しているのに、サーバーが application/x-www-form-urlencoded を受け取っている、またはその逆。あるいは、サーバーが特定のMIMEタイプを期待しているのに application/octet-stream を送っている。
  • 解決策:
    • JSONデータを送る場合は必ず -H "Content-Type: application/json" を指定する。
    • multipart/form-data (ファイルアップロード含む) を送る場合は -F オプションを使用する (curl が自動設定します)。
    • その他の形式(XML, 特定のバイナリなど)の場合は、データの種類に応じた正確な Content-Type-H で指定する。
    • サーバーのAPIドキュメントを確認し、要求される Content-Type を正確に把握する。

11.3. データ形式の間違い

送信するデータの形式自体が、サーバーが期待するものと異なる場合。

  • 問題:
    • JSON構文が間違っている。
    • application/x-www-form-urlencoded 形式で、キー/値の区切りや & の使い方が間違っている。
    • multipart/form-data で、ファイルパスやフィールド名の指定が間違っている。
  • 解決策:
    • JSONデータの送信には、JSONバリデーターなどで構文をチェックする。ファイルから読み込む場合は、エディタで確認する。
    • -d--data-urlencode を使う際は、キーと値のペアが key=value 形式で正しくエンコードされているか確認する。
    • -F オプションを使う際は、フィールド名とファイルパスの指定 (name=@file) が正しいか、ファイルが存在するか確認する。
    • -v オプションを使って送信されるリクエストボディを詳細に確認する。

11.4. ファイルが見つからない、または読み込めない

ファイルの内容をボディとして送信しようとした場合に発生します。

  • 問題: -d @filename, --data-binary @filename, -F 'name=@filename' などで指定したファイルが見つからない、または curl を実行しているユーザーに読み取り権限がない。
  • 解決策:
    • ファイルパスが正しいか確認する(絶対パス、相対パス)。
    • ls -l /path/to/file コマンドなどでファイルが存在することと、読み取り権限 (r) があることを確認する。
    • ファイルパスにスペースや特殊文字が含まれる場合は、適切に引用符で囲む。

11.5. サーバー側のエラー (4xx, 5xx)

curl コマンド自体は正しくても、サーバー側でエラーが発生することがあります。応答のStatus Codeでエラーの種類を把握します。

  • 400 Bad Request: リクエストの構文が不正、またはサーバーが処理できない形式のデータが送られた。ボディの形式、Content-Type、データの値などを再確認する。
  • 401 Unauthorized: 認証情報がない、または間違っている。Authorization ヘッダーや -u オプションを確認する。
  • 403 Forbidden: 認証はできたが、そのユーザーにはリソースへのアクセス権限がない。ユーザーの権限を確認する。
  • 404 Not Found: 指定したURLのリソースが見つからない。URLを確認する。
  • 405 Method Not Allowed: 指定したリソースでPOSTメソッドが許可されていない。APIドキュメントを確認する。
  • 415 Unsupported Media Type: 送信した Content-Type がサーバーでサポートされていない。Content-Type を確認する。
  • 5xx Server Error: サーバー内部でのエラー。サーバー側のログを確認する必要がある。

トラブルシューティングの際は、まず -v オプションを使って curl が実際に何を送信し、サーバーが何を返しているのかを詳細に確認するのが最も効率的な方法です。

12. まとめと次のステップ

本記事では、curl コマンドを使ってPOSTリクエストのボディを送信する様々な方法を詳細に解説しました。

  • -d / --data: 最も一般的で、application/x-www-form-urlencoded または JSON (要 Content-Type: application/json) データを送信する際に使用。ファイルからの読み込みも @filename で可能。デフォルトでPOSTメソッドになり、application/x-www-form-urlencoded ヘッダーを自動追加。
  • --data-raw: -d と似ているが、@ を特別扱いしない。生の文字列データをそのまま送信したい場合に。
  • --data-urlencode: データをURLエンコードしてから送信。application/x-www-form-urlencoded 形式で、エンコーディングを確実に制御したい場合に。
  • --data-binary: バイナリデータをそのまま送信。画像などのファイルアップロードに。Content-Type の明示的な指定がほぼ必須。
  • -F / --form: multipart/form-data 形式でデータを送信。テキストフィールドとファイルアップロードを組み合わせる場合に最適。デフォルトでPOSTメソッドになり、multipart/form-data ヘッダーを自動追加。ファイル指定には @filename または <filename を使用。
  • 標準入力 (-): 一部のオプション (-d, --data-binary, --data-urlencode) は、ファイルパスとして - を指定することで標準入力からデータを読み込める。パイプと組み合わせて動的なデータを送信するのに便利。
  • -H / --header: リクエストヘッダーを指定または上書き。特に Content-Type の指定はPOSTボディ送信において極めて重要。

それぞれのオプションには得意なデータ形式やシナリオがあります。送信したいデータの種類(フォームデータ、JSON、バイナリ、ファイルアップロードなど)と、必要なヘッダー(特に Content-Type)を考慮して、適切なオプションを選択することが重要です。

また、コマンドラインのシェルによる引用符や特殊文字の解釈、そしてサーバーからの応答(特にStatus Code)を確認する習慣をつけることで、POSTリクエストの送信とデバッグがスムーズになります。-v オプションはデバッグの強力な味方です。

curl は非常に多機能なツールであり、本記事で紹介した以外にも多くのオプションがあります。さらに深く学びたい場合は、man curl コマンドでマニュアルページを参照したり、curl の公式ウェブサイト(https://curl.se/ )のドキュメントを読んだりすることをお勧めします。

curl を使いこなすことは、現代の技術スタックで作業する上での貴重なスキルです。本記事が、あなたの curl を使ったPOSTリクエストボディ送信に関する理解を深め、日々の作業に役立つことを願っています。

これで、約5000語の詳細な解説記事は完了です。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール