axiosを使ってPHPにjsonを投げ付ける

表題の件を実装することになったのですが、途中クロスオリジン関係で嵌まったのでメモしておきます。

前提

今回の前提としては下記のような状態です。
  • フロントエンド: Vue.js + axios
  • バックエンド: PHP (dietcake)
  • 開発用PC上でPHPもVue.jsも動作
    • PHPは普通にhttps://localhost/hoge/piyoのようなURL
    • Vue.jsはnpm run serveの開発環境なのでhttp://localhost:8080
      • ここでポート番号が異なるのでクロスオリジンに引っかかる

最初のコード

最初はaxiosのドキュメントにあるサンプルのやり方で試してみました。

Form.vue(JavaScript)

const APIURL = 'http://localhost/app/webroot/'

axios.post(APIURL + 'hoge/piyo', this.senddata)
.then(function (response) {
    console.log(response)
})
.catch(function (error) {
    console.log(error)
})

PHP(hoge/piyo.php)

<?php
if(!ENV_PRODUCTION) {
    header('Access-Control-Allow-Origin: *');
}
$jsonString = file_get_contents('php://input');

file_put_contents("json.json", $jsonString);

exit();
こんな感じ(dietcakeなのでcontrollerとかも記述していますが、ここでは関係ないので省いています)でpost。 すると、
Access to XMLHttpRequest at ‘http://localhost/app/webroot/hoge/piyo’ from origin ‘http://localhost:8080’ has been blocked by CORS policy: Request header field access-control-allow-origin is not allowed by Access-Control-Allow-Headers in preflight response.

と怒られました。

修正コード(途中)

色々試行錯誤した結果、以下のように修正。

Form.vue(JavaScript)

const APIURL = 'http://localhost/app/webroot/'

const axiosApi = axios.create({
    headers: {
        'Content-Type':'application/json'
    }
})

axiosApi.post(APIURL + 'hoge/piyo', JSON.stringify(this.senddata))
.then((response) => {
     console.log(response)
})
.catch((error) => {
    console.log(error)
})

PHP(hoge/piyo.php)

<?php
if(!ENV_PRODUCTION) {
    header('Access-Control-Allow-Origin: http://localhost:8080');
}
header('Access-Control-Allow-Headers: Content-Type');
$jsonString = file_get_contents('php://input');

file_put_contents("json.json", $jsonString);

exit();
主な変更点は以下の通り
  • axios側
    • axiosは予め設定を固定化するためにaxios.create()headersContent-type: application/jsonを指定
    • jsonデータをJSON.stringfyで文字列化
  • PHP側
    • Access-Control-Allow-Originをワイルドカードではなくキチンと指定
    • Access-Control-Allow-Headers指定を追加
これで送信できるようになり、中身にデータが入ったjsonファイルが生成されることを確認しました。

修正コード(最終)

さて、上記のコードを見て分かる方は分かると思うのですが
  • axiosでpostする際のデフォルトのヘッダはContent-type: application/json
  • axiosのサンプルコードではjsonをそのままpostに含んでいた
ので、「実はJS側の修正はいらなかったのではないか?」という疑問が。そこでJSだけを元に戻してみます。

Form.vue(JavaScript)

const APIURL = 'http://localhost/app/webroot/'

axios.post(APIURL + 'hoge/piyo', this.senddata)
.then(function (response) {
    console.log(response)
})
.catch(function (error) {
    console.log(error)
})

PHP(hoge/piyo.php)

<?php
if(!ENV_PRODUCTION) {
    header('Access-Control-Allow-Origin: http://localhost:8080');
}
header('Access-Control-Allow-Headers: Content-Type');
$jsonString = file_get_contents('php://input');

file_put_contents("json.json", $jsonString);

exit();
これでも成功しました……。 ということで、結果的にはPHP側の修正だけで良かった、ということになりました。

余談

PHPでjsonを受け取る際はfile_get_contents('php://input');が一番楽そうだと感じました。

参考

axios

PHPでjsonを受け取る

その他参考

この記事を書いた人

アルム=バンド

フロントエンド・バックエンド・サーバエンジニア。LAMPやNodeからWP、Gulpを使ってejs,Scss,JSのコーディングまで一通り。たまにRasPiで遊んだり、趣味で開発したり。