質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

Q&A

2回答

7833閲覧

CakePHP3でAjaxでPOSTすると400エラーが返る

nnahito

総合スコア2004

CakePHP

CakePHPは、PHPで書かれたWebアプリケーション開発用のフレームワークです。 Ruby on Railsの考え方を多く取り入れており、Railsの高速性とPHPの機動性を兼ね備えています。 MVCやORMなどを「規約優先の考え方」で利用するため、コードを書く手間を省くことができます。 外部のライブラリに依存しないので、単体での利用が可能です。

jQuery

jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

Ajax

Ajaxとは、Webブラウザ内で搭載されているJavaScriptのHTTP通信機能を使って非同期通信を利用し、インターフェイスの構築などを行う技術の総称です。XMLドキュメントを指定したURLから読み込み、画面描画やユーザの操作などと並行してサーバと非同期に通信するWebアプリケーションを実現することができます。

0グッド

0クリップ

投稿2018/09/26 08:19

編集2018/09/26 08:53

やりたいこと概要

ボタン押下

JSでフォームの値を取得

jQueryのAjaxでPOST

CakePHP3でごにょごにょ

JSONを返す

環境など

  • CakePHP3.6
  • PHP7.2

やりたいこと

CakePHP3.6で構築しているWebサービスの表面から、
Ajaxを使ってCakePHPにデータを送りたいと考えています。
しかし、400エラーが常に返されてしまします。
CSRF系が原因かと思うのですが、うまく回避できません。


view

(twig使ってます)

html

1{{ Form.create(null, {'url': Url.build({'controller': 'Hoges', 'action': 'register', 'prefix': 'User'}), 'id': 'creditForm'}) | raw }} 2{{ _view.Form.unlockField('cardNumber') | raw }} 3{{ _view.Form.unlockField('securityCode') | raw }} 4{{ _view.Form.unlockField('expiredMonth') | raw }} 5{{ _view.Form.unlockField('expiredYear') | raw }} 6 7<ul class="form-list-renew"> 8 <li class="item"> 9 <div class="title -required">番号(半角数字)</div> 10 <div class="form-group"> 11 {{ Form.control('cardNumber', { 12 'required': true, 13 'error': false, 14 'type': 'number', 15 'class': '', 16 'label': '', 17 'placeholder': '例)1234567890123456' 18 }) | raw }} 19 </div> 20 </li> 21 <li class="item"> 22 <div class="title">コード(半角数字)</div> 23 <div class="form-group -securitycode"> 24 {{ Form.control('securityCode', { 25 'required': true, 26 'error': false, 27 'type': 'number', 28 'class': '', 29 'label': '', 30 'placeholder': '例)000' 31 }) | raw }} 32 </div> 33 </li> 34 <li class="item"> 35 <div class="title">期間</div> 36 <div class="form-group"> 37 <div class="select-box"> 38 <label> 39 {{ Form.control('expiredMonth', { 40 'required': true, 41 'error': false, 42 'type': 'select', 43 'class': '-sec_code -limit', 44 'label': '', 45 'empty': '選択してください', 46 'options': 1..12 47 }) | raw }} 48 <i class="if if-top_arrow_down"></i> 49 <span></span> 50 </label> 51 <label> 52 {{ Form.control('expiredYear', { 53 'required': true, 54 'error': false, 55 'type': 'select', 56 'class': '-sec_code -limit', 57 'label': '', 58 'empty': '選択してください', 59 'options': years 60 }) | raw }} 61 <i class="if if-top_arrow_down"></i> 62 <span></span> 63 </label> 64 </div> 65 </div> 66 </li> 67</ul> 68{{ Form.end() | raw }}

javascript

1let map = $('form#creditForm').serialize(); 2 3$.ajax({ 4 url: '{{ Url.build({"url": Url.build({"controller": "Hoges", "action": "register", "prefix": "User"}) }}', 5 type: 'POST', 6 data: map, 7 dataType: 'json', 8 contentType: 'application/json; charset=utf-8', 9 beforeSend: function (xhr) { 10 xhr.setRequestHeader("X-CSRF-Token", csrf); 11 }, 12}).done(function (json) { 13 {# 処理失敗 #} 14 if (json['success'] === false) { 15 alert('エラー'); 16 return false; 17 } 18 19 alert('登録しました'); 20}).fail(function (jqXHR, textStatus, errorThrown) { 21 alert('登録失敗しました'); 22});

controller

php

1public function register() 2{ 3 return $this->response 4 ->withType('application/json') 5 ->withStringBody(json_encode(['success' => true, 'message' => ''])); 6}

※ここに書いている情報は、コードの一部を抜き出したもので、若干マスキングしたときにタイポがあるかもしれません。ご了承ください

上記のように、

beforeSend: function (xhr) { xhr.setRequestHeader("X-CSRF-Token", csrf); },

を入れたり、unlockFieldを入れたりしているのですが、
結局400が返ってきます(Laravelだとうまくいくのに…)…。
この原因の解決策をご存知の方がいらっしゃいましたら、ご教示いただけますと幸いです。

よろしくお願いいたします。

追記

CakePHPのエラー

Error: [Cake\Controller\Exception\AuthSecurityException] '_Token' was not found in request data.

'_Token' was not found in request data in CakePHP3 after server migrationを見る限り、
これで行けそうな気がするんですが…

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

popobot

2018/09/26 08:28

CakePHPでどのExceptionが発生して400エラーになっているかログ等から確認して、掲載してください。また、js側のcsrfという変数には正しくCSRFトークンが入っているのか確認してください。
nnahito

2018/09/26 08:33

エラー記載しました。JSにはCSRFトークン入ってます。
popobot

2018/09/26 08:35

AuthSecurityExceptionなので、CSRFではなく、セキュリティコンポーネントでエラーになっていますね...
popobot

2018/09/26 08:42

フォームのinputをすべてシリアライズして送っているのでよさそうですけどね... _Tokenというhiddenなinputがあるはずなのですが、フォームに存在するのでしょうか。ブラウザの開発ツールなどで見てみてください。
nnahito

2018/09/26 08:42

あー、CSRFかと思ってました……こちら原因って何なのでしょうか?
nnahito

2018/09/26 08:44

あ、「_Token[fields]」とか「_Token[unlocked]」がありますね
popobot

2018/09/26 08:45

はい、CSRFではないですね。雑にセキュリティコンポーネントを無効にしてみるとうまくいくと思います。一部のURLだけを無効にする方法もあります。
nnahito

2018/09/26 08:49

うぅん、会社のやつなので、雑に無効化はやりたくないですね…w
popobot

2018/09/26 09:20

だとすると、js側で_Tokenを遅れてないんですかね
nnahito

2018/09/26 09:27

一つR&Dで見つけ出したのですが、ajaxの「beforeSend」の部分を消すとうまくいきました…ヘッダーに入れるとだめになったんでしょうか…
popobot

2018/09/26 09:35

うーん、なんでしょうね...自分もCakePHP3.6+jQueryで同じような処理を書いていますが、問題なく動いているので...謎です(beforeSendを使ってCSRFトークンもセットしています)
nnahito

2018/09/26 10:02

あれー……なんでだ……これは不思議すぎる。エラーの可能性があるとしたら、やはりAppControllerなのでしょうか?
popobot

2018/09/26 10:59 編集

AuthSecurityExceptionは、セキュリティコンポーネントがthrowする例外です。セキュリティコンポーネントは、POSTされたデータがフォームの項目と比較して改ざんされていないかチェックしていますが、処理全体の早い段階(startup)で実行されます。 そして_Tokenというのは、フォームの項目をハッシュにしたデータなどが入っています。
popobot

2018/09/26 10:29

「ajaxの「beforeSend」の部分を消すとうまくいきました」とありますが、これを消すと_Tokenが送信されるけど、消さないと送信されないということなのでしょうか
popobot

2018/09/26 10:32 編集

DebugKitを使っているなら、Historyタブを見ると、Ajaxで送信したデータの内容が見れるので、活用すると調査しやすいと思います。HIstoryタブで、対象のAjaxの処理を選択した後、Requestタブをみると過去のリクエストのデータを見ることができます
guest

回答2

0

ソースを見る限り、
xhr.setRequestHeader("X-CSRF-Token", csrf);
のcsrfが空のように思えますが、どこかで値が代入されているのでしょうか?
追記のリンク先にも書かれているように
$('[name="_csrfToken"]').val()
を格納する必要があると思います。

投稿2018/10/03 04:40

njgit3448

総合スコア18

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

$.ajaxの「url:」には実際には何が指定されているのでしょうか?
ブラウザの開発ツールからアクセス先を確かめ、そのurlが存在するか確認してみてください

投稿2018/09/26 10:08

yambejp

総合スコア114769

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

nnahito

2018/09/26 10:15

ご回答有り難うございます。 正常なURL(GETアクセス可能)が指定してありますので、そこは問題ない気がします…>< CakePHPは、存在しないURLにPOSTすると400を返すのでしょうか?
yambejp

2018/09/26 10:20

おっと失礼400エラーは「不正なリクエスト」に対するエラーですね APIなどで想定したデータ形式と違う場合に返すので mothodが違ったり要求項目がちがったり所定のcookieなどの環境ができてなかったりしたときに 意図的に吐いている可能性があります
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問