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

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

ただいまの
回答率

90.12%

Ajax通信が行われた際の、変数や関数について

受付中

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 374

toll_tree

score 29

こちらの記事にて、ajax通信に関連する処理を学習していた際に、分からない部分があった為、ご質問させて貰いました。
以下のコードはすべてリンクに掲載されていたものになります。
下記は、「practice_js.html」です

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>ajax_practice</title>
</head>
<body>
  <h1>設定</h1>
  <p>
    年齢:<input type="text" id="age" value="24"><br>
    職業:<input type="text" id="job" value="学生"><br>
    <input type="button" id="execute" value="送信"><br>
  </p>
  <h1>結果</h1>
  <p>
    可否:<input type="text" id="result" value=""><br>
    内容:<input type="text" id="detail" value=""> <br>
  </p>
  <script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
  <script src="default.js"></script>
</body>
</html>


下記は、api.phpです。

<?php

// Content-TypeをJSONに指定する
header('Content-Type: application/json');

// $_POST['age']、$_POST['job']をエラーを出さないように文字列として安全に展開する
$age = (string)filter_input(INPUT_POST, 'age');
$job = (string)filter_input(INPUT_POST, 'job');

// 整合性チェック
if ($age === '' || $job === '') {
    $error = '年齢と職業を両方入力してください';
} else if (!ctype_digit($age)) {
    $error = '年齢は正の整数で入力してください';
} else if (($age = (int)$age) > 100) {
    $error = '生きすぎィ!';
}

if (!isset($error)) {
    // 正常時は 「200 OK」 で {"data":"24歳、学生です"} のように返す
    $data = "{$age}歳、{$job}です";
    echo json_encode(compact('data'));
} else {
    // 失敗時は 「400 Bad Request」 で {"error":"..."} のように返す
    http_response_code(400);
    echo json_encode(compact('error'));
}


下記は、「default.js」です

/* エラー文字列の生成 */
function errorHandler(args) {
  var error;
  // errorThrownはHTTP通信に成功したときだけ空文字列以外の値が定義される
  if (args[2]) {
      try {
          // JSONとしてパースが成功し、且つ {"error":"..."} という構造であったとき
          // (undefinedが代入されるのを防ぐためにtoStringメソッドを使用)
          error = JSON.parse(args[0].responseText).error.toString();
      } catch (e) {
          // パースに失敗した、もしくは期待する構造でなかったとき
          // (PHP側にエラーがあったときにもデバッグしやすいようにレスポンスをテキストとして返す)
          error = 'parsererror(' + args[2] + '): ' + args[0].responseText;
      }
  } else {
      // 通信に失敗したとき
      error = args[1] + '(HTTP request failed)';
  }
  return error;
}

// DOMを全て読み込んだあとに実行される
$(function () {
  // 「#execute」をクリックしたとき
  $('#execute').click(function () {
      // Ajax通信を開始する
      $.ajax({
          url: 'api.php',
          type: 'post', // getかpostを指定(デフォルトは前者)
          dataType: 'json', // 「json」を指定するとresponseがJSONとしてパースされたオブジェクトになる
          data: { // 送信データを指定(getの場合は自動的にurlの後ろにクエリとして付加される)
              age: $('#age').val(),
              job: $('#job').val(),
          },
      })
      // ・ステータスコードは正常で、dataTypeで定義したようにパース出来たとき
      .done(function (response) {
          $('#result').val('成功'); 
          $('#detail').val(response.data);
      })
      // ・サーバからステータスコード400以上が返ってきたとき
      // ・ステータスコードは正常だが、dataTypeで定義したようにパース出来なかったとき
      // ・通信に失敗したとき
      .fail(function () {
          // jqXHR, textStatus, errorThrown と書くのは長いので、argumentsでまとめて渡す
          // (PHPのfunc_get_args関数の返り値のようなもの)
          $('#result').val('失敗');
          $('#detail').val(errorHandler(arguments));
      });
  });
});


お聞きしたい点は2点です。
ajax通信が成功した際に処理される、「done」メソッド内の「$('#detail').val(response.data);」ここの「data」は、「api.php」の「echo json_encode(compact('data'));」ここの配列「data」のことを指しているのでしょうか?
もう一点目は、失敗した場合のfailメソッド内の「 $('#detail').val(errorHandler(arguments));」ここの「arguments」です。errorHandler関数の中身から、配列かとは思うのですが、ajax通信行われた際に用意される特殊なものなのでしょうか?
どなたか、教えて頂けましたら幸いです。
よろしくお願いします。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • 退会済みユーザー

    2019/05/14 19:11

    複数のユーザーから「やってほしいことだけを記載した丸投げの質問」という意見がありました
    「質問を編集する」ボタンから編集を行い、調査したこと・試したことを記入していただくと、回答が得られやすくなります。

回答 2

+2

質問に直接関係ある部分ではないですが、気になった点。

$age = (string)filter_input(INPUT_POST, 'age');
$job = (string)filter_input(INPUT_POST, 'job');


安易なキャストは潜在的なバグを増やすだけになるのでやめたほうが良いです。
それにせっかく filter_input()を使っているのですから機能をきちんと使いましょう。
フラグ次第ですが、デフォルトではキーが存在しなかったらnull、filterに失敗したらfalseが返ってきます。
型が気になるなら検証フィルタかけてチェックすればそもそもageにかけてるctype_digit()のチェックも不要になります。

それに、もしage,jobが配列で送信されたらどうなると思いますか?
チェックボックスでなくてもnameに[]で設定すれば配列で送信されます。
そうなるとキャストでstringにしてしまってはバグに気づけなくなります。

ajaxとのことで実行されるプログラムは独立したアプリケーションとして動作しているものなので、
「必ずあるところから呼び出される前提」「くる情報の形が決まっている」「強制変換」は不具合を潜在化し、問題の切り分けを困難にします。
(くる情報が決まってるならなおさらキャストの必要はないですけど)


} else if (($age = (int)$age) > 100) {


ここもそうですね。ただ、ここは=になっている意味が分かりませんが。


if (!isset($error)) {


バリデーションの結果が必ず1つしか引っかからないというあまりよくない前提が含まれています。
「job」がどういう風にデータが送られるのかわかりませんが、例えば「セレクトボックスなど選択肢から選ばれる」という場合、「選択肢にないものが選ばれたらNG」とする必要が出てきます。
となると「ageが数字でない」と「選択肢にないものが選ばれる」は同時に起きうる現象になりますよね。
そのあたりも想定するのでしたら$errorは配列にしておくべきと思います。

$error = [];

/*
バリデーション
*/

if(count($error) === 0){
 //バリデーションOK
}else{
 //バリデーションNG
}

    $data = "{$age}歳、{$job}です";
    echo json_encode(compact('data'));

入力値が正常でそのまま返しているだけならわざわざPHPで文字列作る必要ないのでは。

ajaxのdoneで受け取れる引数の
jqXHR.done(function( data, textStatus, jqXHR ) {});
textStatusで判断しても良いと思います。

    "success"
    "notmodified"
    "error"
    "timeout"
    "abort"
    "parsererror"


「返すのがJSON」というのが決まっていてとりあえずOKだったと返したいなら配列を直接突っ込んでjson_encode()すれば良い話ですし。

echo json_encode(['result'=>'0']);

http_response_code(400);
echo json_encode(compact('error'));

1つ前にあわせてこんな感じで。

echo json_encode(['result'=>'9','error'=>$error]);

ここでcompact()って微妙な感じはするので私はより明示的に連想配列を作って返すことが多いです。
まあここは好みで(あと現場のルールがあればそれに従う、と)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/10 15:25

    mpywさん自体は私よりも広く深い知見と技術力をお持ちなのは間違いありませんので(teratailでの活動からも伺い知れます)、
    私の回答はmpywさんのコード・記事を非難する意図は全くないことを付け加えておきます。

    キャンセル

  • 2019/05/10 20:30

    今、掲示してもらったご回答の内容と、コードを見返していたのですが、ちょっとちんぷんかんぷん状態になっています...
    ajaxに関しては、ある程度ザッと理解できる程度でも大丈夫ですかね?
    下記の記事については理解できましたが、mpywさんの記事のコードは少し難しく感じてしまいます...
    https://qiita.com/okumurakengo/items/53020dd97382d49621ce

    キャンセル

  • 2019/05/10 20:54

    結局リクエストとレスポンスの根本部分が理解できてないからかと。
    あれで難しいとなると本当に基礎の基礎とリファレンスの使い方が抜けてるということになりますね。

    キャンセル

+1

dataはそうです。argumentsは関数内でアクセスできる特殊なオブジェクトです。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Functions/arguments

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/05/09 21:32

    分かりました。一度確認してみます!

    キャンセル

  • 2019/05/10 20:22

    エラーを発生させて、console.log(arguments)としてみましたら、以下のように表示されました。
    「Arguments(3) [{…}, "error", "Bad Request", callee: ƒ, Symbol(Symbol.iterator): ƒ]
    0: {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
    1: "error"
    2: "Bad Request"」
    上記には、「readyState:」とあったのですが、XMLHttpRequestオブジェクトと関係があるものでしょうか?
    やはり、「arguments」が何か分かっておらず、理解が進まないといった状況になってしまっております。。

    キャンセル

  • 2019/05/10 23:33

    failのコールバック関数の引数が詰まっているオブジェクトです。あまり難しく考えなくてよいと思います。

    jQueryのドキュメント(http://api.jquery.com/jquery.ajax/)には、fail時のコールバック関数は「jqXHR.fail(function( jqXHR, textStatus, errorThrown ) {});」のように記述されています。まさにそれら3つが詰まっているだけです。

    キャンセル

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

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる