Node.js(Express)で組んだプログラムにcurlを使ってJSONデータをPOSTしようとしました。
結果どハマりしたのでメモ。
結論
解決してない。なんたる出オチ。
もし同じようにハマってる人がいたら俺の屍を越えてゆけ・・・!
僕は他の方法でJSONデータをPOSTする事にしました。
環境
Win10+VSC@1.68+Node.js@16.14.2+Express@4.18.1
VSCのターミナルはPowerShell使用
やろうとしたこと
- expressで書いたプログラムにJSONデータをPOSTしてJSONデータを返す
- VSCのターミナルからcurlコマンドでJSONデータをPOST
やったこと
さっくりExpressの公式ドキュメントを参考にPOSTデータを受け取るプログラムを書きます。
POSTして、プログラム側で受け取ったデータの中身はreq.bodyに入っている模様。
なので公式ドキュメントのreq.bodyについての項目を参照。
index.js
var express = require('express')
var app = express()
app.listen(3000)
console.log('Server : online')
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.post('/', function (req, res) {
console.log(req.body)
res.json(req.body)
})
下記コマンドでサーバを起動
node index.js
↓
Server : online
body-parserはどうした?
→最新版のExpressはbody-parserが標準で組み込まれているのでbody-parserのインストールや記述なしでOK。
これでhttp://localhost:3000
にコマンドを投げる準備ができました。
curlコマンドはInvoke-requestに置き換えられる
JSONデータPOST用のcurlコマンドはこれ
curl -X POST http://localhost:3000 -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"name":"tanaka"}'
結果
→Invoke-WebRequest : パラメーター 'Headers' をバインドできません。
いきなりエラーです。たまらん。
これはVSCのターミナル(PowerShell)でcurlコマンドは、PowerShellの標準搭載コマンドであるInvoke-webRequestのコマンドにエイリアスされている為。
つまり「curl hogefuga」のようなコマンドを打つと「Invoke-WebRequrest hogefuga」というコマンドを打ちましたねアナタ!!って自動的に解釈してくれるという事。
「PowerShell curl エイリアス」でググったり
こちらのサイトさんを参考にしたりしながらエイリアスを無効化しました。
最初はプロファイル自体が存在しなかったのでファイルを作るところからやってます。
ちなみにプロファイルを置く場所は全ユーザに効くか個別ユーザだけの設定するかによって変わるようですが、全ユーザに効くようにするならecho $Profile.AllUsersAllHosts
のコマンドをPowerShellで打つと実際のパスが分かります。
自環境に応じて適切な場所に置いてあげて。
curlコマンドを実行してみる
結果
→SyntaxError: Unexpected token n in JSON at position 1
at JSON.parse () うんたらかんたら
またエラーです。プログラムとはエラーとの戦いの歴史である。
JSON.ParseがなんたらってあるのでJSONに関する場所が怪しい?
とりあえずapp.use(express.json())
はコメントアウト、res.json(req.body)
は res.send(req.body)
に置き換えてみる。
実行してみる
curl -X POST http://localhost:3000 -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{"name":"tanaka"}'
→{}
何も入ってない。打ったcurlコマンドは先ほどと同じJSONデータをPOSTする文字列なのでそういうもんなんだろう、という事で次に進む。
JSONじゃないデータをPOSTしてみる
curl -X POST http://localhost:3000 -d "tanaka"
結果
node側(console.log(req.body)の結果) → { tanaka: '' }
PowerShell側(res.send(req.body)) → {"tanaka":""}
JSONとして格納されてるしJSONとして返しているのかな?
調べたらres.sendとres.jsonはほぼ似た動きをするのだとか。なるほど。
ヘッダ情報をつけないでJSON形式をPOSTしてみる
curl -X POST http://localhost:3000 -d "{name:tanaka}"
結果
node側(console.log(req.body)の結果) → { '{name:tanaka}': '' }
PowerShell側(res.send(req.body)) → {"{name:tanaka}":""}
違う、そうじゃない。
データの内容の書き方を変えてみる。
curl -X POST http://localhost:3000 -d "{'name':'tanaka'}"
結果
node側(console.log(req.body)の結果) → { '{name:tanaka}': '' }
PowerShell側(res.send(req.body)) → {"{'name':'tanaka'}":""}
違う、そうじゃない。(2回目)
色々調べてみた結果下記のcurlコマンドでJSONデータでの格納と応答を得る事ができました。
PowerShell側の引数をreq.bodyからreq.body.nameにするときちんとtanaka
が返ってきます。
curl -X POST http://localhost:3000 -d "name=tanaka"
結果
node側(console.log(req.body)の結果) → { name: 'tanaka' }
PowerShell側(res.send(req.body)) → {"name":"tanaka"}
でもこれはJSONを渡す&node側でJSONを受け取っていることにならないしなぁ・・・
app.use(express.json())の封印を解いてみる
コメントアウトしていたapp.use(express.json())
を戻してさっき打ったcurlコマンドを打ってみる。
curl -X POST http://localhost:3000 -d "name=tanaka"
結果
node側(console.log(req.body)の結果) → { name: 'tanaka' }
PowerShell側(res.send(req.body)) → {"name":"tanaka"}
普通にコマンドも通ってるようなのでコメントアウトしていた部分はとりあえず問題ないとみていいのかな?
JSONデータっぽい内容を打ってみる。
curl -X POST http://localhost:3000 -d "{'name':'tanaka'}"
結果
node側(console.log(req.body)の結果) → { '{name:tanaka}': '' }
PowerShell側(res.send(req.body)) → {"{'name':'tanaka'}":""}
違う、そうじゃない(3回目)
じゃあなんですか、やっぱりヘッダが要るんですね?
curl -X POST http://localhost:3000 -H 'Content-Type: application/json' -d "{'name':'tanaka'}"
結果
SyntaxError: Unexpected token ' in JSON at position 1
at JSON.parse (<anonymous>)うんたらかんたら
メイのバカ!もうしらない!!!
視点を変えてみる
一通り試してみて最初のところに戻ってきたのでアプローチを変えてみます。
そもそも論としてcurlはただのツール。VSC上でJSONをPOSTできてnode.jsで書いたプログラミングの動作チェックができればいいのです。
どうやら REST Client というVSCの拡張機能でHTTPリクエストを簡単に投げられる模様。
REST Clientを使ってJSONデータをPOSTしてみる
早速インストールして.httpファイルを作ってJSONデータをPOSTしてみます。
POST http://localhost:3000 HTTP/1.1
content-type: application/json
{
"name": "tanaka"
}
Response
HTTP/1.1 200 OK
X-Powered-By: Express
Content-Type: application/json; charset=utf-8
{
"name": "tanaka"
}
---
node側(console.log(req.body)の結果) → { name: 'tanaka' }
ちゃんとJSON受け取ってJSON返してくれてるじゃん!!
じゃあなんですか、curlコマンドが間違ってたってことですか?
Invoke-requestも試してみる?
め、めんどくせ~~~
となったところで投了です。おとなしく REST Client 使います。
どうしてもcurlでJSONデータをPOSTしなきゃいけない人にとってはお力になれずすみません。
POSTできりゃいいよって人はハマったら REST Client をどうぞ。