axiosでPOSTしたデータがサーバのPHPの$_POSTで取得できない

axiosでpostしたオブジェクトはjson形式でサーバに送られる。content-typeはapplication/jsonで送られる。PHPはこれを$_POSTに入れない。通常のhtmlのformで送られるデータとはcontent-typeも中身も違う。このjsonで送られたデータをどうやってPHPで取得すればいいか。

axiosでformDataを送る

1つの解決法はaxiosでPOSTするときにフォーム形式で送る方法。これはオブジェクトの代わりにformDataを設定する方法とcontent-typeを設定する方法があるようだがここでは考えずサーバで対応する方法を考える。

PHPでjsonを受け取る

ここではapache2+PHPのサーバを考える。その前にクライアントからポストしたデータ(HTTPのボディ)はどのように扱われるのだろうかをはっきりさせたい。

PHPのマニュアルによるとcontent-typeがapplication/x-www-form-urlencodedmultipart/form-dataの場合は$_POSTにデータが入るらしい。マルチパートというのはもともとは1つのファイルに複数のファイルを埋め込む方式でメールなどで添付ファイルを送るときに使われたものだと思う。境界となる長い文字列を設定し、それでファイルを分割する。大きいファイルを送るとき、あるいは単にファイルをおくるときはブラウザはこの形式を使うのかもしれない。あるいはバイナリを送りたいときエンコードを指定して送るから必要になるのかもしれない。

いずれにしろ$_POSTにデータが入るのはこの2つの場合だけなのでapplication/jsonの場合は$_POSTには入らない。ではどこへ行くのか?あるいは単に捨てられてしまうのだろうか。

php://input

結論を言うとここにあるように、php://inputに行くらしい。これはPHPにおいて標準入力を表すときにphp://stdinなどと書くが、php://inputはPHPによってHTTPボディからの入力にリダイレクトされていてPHPスクリプトからはここから読み込めばHTTPボディが取得できることになる。

jsonの取得

今回のデータはjson形式なのであとはこれを$_POSTに変換してあげればその他のコードは変更せずに動くはず。

元のサイトのコードが少しおかしかったので修正した。

以下のようにpostmanで送るとPHPで取得できた。

apacheでjsonを返す時httpヘッダを追加する

特殊なhttpレスポンスヘッダがあるとクライアントのjsからドメイン制限を無視して取得できる。apache2で設定する方法。

mod_headers.cを有効にする

サーバのjsonを置いたディレクトリに.htaccessを置き、ここに以下の記述を追加する。
(.htaccessが有効になっている必要がある。有効になってない場合はサーバの設定ファイルに直接書くか、有効にする)

ヘッダが帰ってきているかChromeで確認

Chromeで対象jsonを開き、[Ctrl]+[Shift]+Iでdevコンソールを開き「ネットワーク」タブの「All」を開く。[Ctrl]+Rと表示されたときは押す。

chromeのDEVツール。ネットワークタブでCtrl+R

ChromeのDEVツール。3xxが返ってくる

3xxが帰ってきているときは[Shift]を押しながらリロードする。

ChromeのDEVツール。200が返ってくる

対象ファイルをクリックするとヘッダが見れる。

ChromeのDEVツール。HTTPヘッダが見れる

javascriptで試す

node + vscode が前提。ここではjsonの取得にaxiosモジュールを使ってみる。

axiosのインストール

vscodeのターミナルで以下を実行。

htmlの作成

axiosで取得したjsonを表示した

リンク

このリンクのhtmlのjavascriptはhttps://jsonplaceholder.typicode.com/postsから取得している。次の例はこのサーバから取得。

.htaccessはすべてのクライアントから許可するように以下のように修正

リンク

このリンクが外部のクライアントからアクセスされた時のログは以下

サーバとクライアントとクロスサイトスクリプティングが一緒になって複雑