curlコマンドとFetch APIとの対応についてまとめてみました

  •  
 
トビウオ2021年5月19日 - 15:48 に投稿

概要

HTTPリクエストをcurlで試行したりFetch APIで実装したりする際、「この処理はどう書くんだけ?」といったことが稀によくあります

そこで、詰まりがちな点についてサンプルコードを挙げつつまとめてみました。

傾向と対策

URLの書き方

基本的にはそのまま書けばいいです。curlの場合は最後のコマンドライン引数、Fetch APIの場合は第一引数で指定します。どちらのコマンドも、デフォルトではGETリクエストとして扱います。

curl http://www.example.com
fetch('http://www.example.com')

ただ、curlでGETパラメーターを指定する際は注意が必要です。1つだけなら問題ありませんが、2つ以上指定して「&」が間に挟まる際、「\&」とバックスラッシュを挿入するか、URL全体を引用符で囲む必要があります。

また、-Gオプションを付与すると強制的にGETリクエストになりますので、-dで指定したデータが全てGETパラメーターとして付与されるようになります。

# 全て同じ意味
curl http://www.example.com?a=foo\&b=bar
curl 'http://www.example.com?a=foo&b=bar'
curl -G -d a=foo -d b=bar http://www.example.com
fetch('http://www.example.com?a=foo&b=bar')

POSTメソッドの書き方

GET以外のHTTPメソッドを使用する場合、curlの場合は-Xオプションで指定します。ただし、リクエストボディを設定している場合、-Xを指定しなくとも自動でPOSTリクエストとなります。

# 同じ意味
curl -X POST -d a=foo -d b=bar http://www.example.com
curl -d a=foo -d b=bar http://www.example.com

curlでPOSTする際、デフォルトではContent-Typeapplication/x-www-form-urlencodedとして送信されます。-dではなく-Fと指定すれば、multipart/form-dataとして送信されます。

curl -F a=foo -F b=bar http://www.example.com

Fetch APIで実装する際は、FormData型をPOSTすると、Content-Typemultipart/form-dataとして送信されます。また、URLSearchParams型をPOSTすると、application/x-www-form-urlencodedとして送信されます。

// 例1
const formData = new FormData();
formData.append('a', 'foo');
formData.append('b', 'bar');
fetch('http://www.example.com', {method: 'POST', body: formData});

// 例2
const params = new URLSearchParams();
params.append('a', 'foo');
params.append('b', 'bar');
fetch('http://www.example.com', {method: 'POST', body: params});

ファイルをPOSTする場合

curlの場合、キー=@ファイル名と指定することにより、ファイルをPOSTすることができます。ただし、紛らわしいことに、-d--data-binary--data-urlencodeという3種類の指定方法があり、それによって@ファイル名に対する挙動が変わります。

# ファイル内の改行が削除された状態で送信
curl -d a=@foo.txt http://www.example.com

# ファイル内の改行はURLエンコードして送信
curl --data-urlencode a=@foo.txt http://www.example.com

# そのまま送信
curl --data-binary a=@foo.txt http://www.example.com
# (キーを指定しない場合)
curl --data-binary @foo.txt http://www.example.com

Fetch APIの場合、File型やBlob型のオブジェクトを送ったり、直接文字列を送信することができます(--data-binaryと同じ挙動)。

// 例1 (File型は<form>から取得したり自作したりできる)
const formData = new FormData();
const file = new File(['foo'], 'foo.txt', {
  type: 'text/plain',
});
formData.append('a', file);
fetch('http://www.example.com', {method: 'POST', body: formData});

// 例2
fetch('http://www.example.com', {method: 'POST', body: file});

ヘッダーを指定する場合

curlの場合、-Hオプションから、リクエストヘッダーを指定することができます。ただし、Cookieやユーザーエージェントなど、よく使うものについては専用オプションが用意されています。

curl -H a:foo -H b:bar 'http://www.example.com'
# Cookie
# この場合は、「Cookie: a=foo;b=bar;」
curl -b 'a=foo;b=bar;' 'http://www.example.com'
# ユーザーエージェント
# この場合は、「User-Agent: Mozilla/5.0」
curl -A 'Mozilla/5.0' 'http://www.example.com'
# リファラー
# この場合は、「Referer: http://www.example.com/foo/bar」
curl -e 'http://www.example.com/foo/bar' 'http://www.example.com'
# ユーザー認証。ここではBASIC認証。
# この場合は「Authorization: Basic dXNlcjpwYXNz」
curl -u user:pass 'http://www.example.com'

一方Fetch APIの場合、専用オプションは存在せず、いずれも手動で設定する必要があります。何でも変更できるわけではなく、設定できないヘッダー名があるので注意が必要です。

Cookieについては自前で設定できませんので、credentials: 'include'オプションを設定して、自分のドメインが持つCookie情報を自動で送るようにするのがせいぜいでしょうか。

リファラーはheadersではなくreferrerから指定します。ユーザーエージェントを指定することは禁止されていませんが、Webブラウザによってはこれを無視します

const headers = new Headers();
headers.append('a', 'foo');
headers.append('User-Agent', 'Mozilla/5.0');
headers.append('Authorization: Basic ', btoa('user:pass'));
fetch('http://www.example.com', {
  headers: headers,
  referrer: 'http://www.example.com/foo/bar',
});

なお、よく使いそうなContent-TypeAcceptは、curlにも専用オプションがありません。前者はcurlだと幾つかのケース(前述)で自動設定されますが、後者はうっかりしがちなので注意しましょう。

JSON文字列を送信したい場合

curlだと、そのまま文字列を送り込むか、@ファイル名としてファイル読み込みを使うことになります。しかしFetch APIの場合、JSON.stringifyを使うことで、JavaScriptオブジェクトをJSON化して送信できます。

fetch('http://www.example.com', {
  method: 'POST',
  body: JSON.stringify({
    'a': 'foo',
    'b': 'bar'
  })
});

おまけ

curlコマンドから、各種プログラミング言語用のコードに変換するWebサイトが存在します。こちらを利用すれば、上記で書いたことを覚えなくてもサクッと変換できます。

Convert curl syntax to Python, Ansible URI, MATLAB, Node.js, R, PHP, Strest, Go, Dart, Java, JSON, Elixir, Rust

……ただ、このサイトの変換は完璧ではありません。例えば以下の点に気をつけて、変換後は動作を確かめて使いましょう。

  • curl http://www.example.com?a=foo\&b=bar」を「fetch('http://www.example.com?a=foo\&b=bar');」と訳してしまう
  • -d」指定に対し、「application/x-www-form-urlencoded」であることをリクエストヘッダーに訳さず、「--data-urlencode」「-F」指定に至っては無視してしまう
  • -d @foo.txt」を「body: 'a=@foo.txt'」と訳してしまう
  • -e」指定を無視してしまう

コメントを追加

プレーンテキスト

  • HTMLタグは利用できません。
  • 行と段落は自動的に折り返されます。
  • ウェブページのアドレスとメールアドレスは自動的にリンクに変換されます。
CAPTCHA
この質問はあなたが人間の訪問者であるかどうかをテストし、自動化されたスパム送信を防ぐためのものです。