简体   繁体   中英

Is there a more proper way to handle errors using AJAX?

I've never asked anything here, but there's something that bugs me.

You see, I'm toying with PHP for about a year. I've made myself quite a big project while learning PHP, JQuery, MySQL, etc.- it's far from being perfect, or even being finished, but it works and I'm constantly trying to improve existing code while adding new functions. It's a text-based browser MMORPG game (it's still in development), if you want a link, I'll provide it, but I didn't come here to promote it.

The thing is, I feel okay in procedural PHP (though I still have problems with repeating code), so I've decided it's about time to move to OOP. I understand it in theory, know the basics, and I'm slowly advancing in practice, but I wanted your advice, before moving too far.

In my original game with procedural code, I'm often doing something along these lines:

  • user visits a page, say a shop.php. On opening the site, shop.php retrieves from database list of items that are available to buy. There are blank #success-message and #error-message paragraphs on the site.
  • user then can choose an item from shop he wants to buy- clicking the item triggers javascript, and an AJAX call is made to the buy-item.php , expecting a json to be returned
  • in buy-item.php I'm creating an array, say, $result("success" => 0, "message" => "")
  • buy-item.php checks if the player can afford the item, has space in backpack, etc., and if there's one condition that isn't met, then $result["message"] sets to, say, "You need more gold". If all conditions are met, then result["success"] set's to 1, and $result["message"] to, say, "Purchase successful". Finally, it echoes json_encode($result) to AJAX.
  • in AJAX success: I check if(result.success) , and act accordingly- If purchase was successful, I'd do $("#error-message").html(result.message) , and if it was successfull, I'd put result.message in "#success-message" instead (I could display both error and success messages in the same paragraph I guess, but that's simpler for me to do it separately, because these messages are styled differently, say, success is colored green, and error- red).

Now, is that a correct approach to handle errors? Or should I code it completely differently? Will this approach be still valid in OOP?

Let me show you what I mean with this example, I'm toying with at the moment ( for simplicity sake, please forget about security or even usefulness of the code ):

index.php

<!DOCTYPE html>
<html lang="pl-PL">
    <head>
        <meta charset="UTF-8">
        <script
            src="https://code.jquery.com/jquery-3.2.1.min.js"
            integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
            crossorigin="anonymous">
        </script>
        <script src="script.js"></script>
    </head>
    <body>
        <div id="wrapper">
            <p id="error-message"></p>
            <p id="success-message"></p>
            <form id="registration-form" method="post">
                <input type="text" placeholder="Account Name" name="nickname"></input>
                <input type="text" placeholder="Password" name="password"></input>
                <input type="text" placeholder="E-mail" name="email"></input>
                <button type="submit">Register</button>
            </form>
        </div>
    </body>
</html>

User.php

<?php

class User{        
    //register method
    public function register($nickname, $password, $email){
        $result = array("success" => 0, "message" => "");
        //example validation
        if($nickname==123){
            $result["message"] = "Could not register.";
        }
        else{
            //add user to the database
            //sql code here
            $result["success"] = 1;
            $result["message"] = "Registration successful.";
        }
        return $result;
    }
}

?>

registerProcessing.php

<?php
    require_once 'User.php';

    $user = new User();

    echo json_encode($user->register($_POST["nickname"], $_POST["password"], $_POST["email"]));
?>

script.js

$(function() {

    $("#wrapper").on("submit", "#registration-form", function(e){
        e.preventDefault();
        $.ajax({
            type: "POST",
            url: "registerProcessing.php",
            data: $("#registration-form").serialize(),
            dataType: "json",
            success: function(result){
                if(result.success){
                    $("#success-message").html(result.message);
                }
                else{
                    $("#error-message").html(result.message);
                }
            }
        });
    });

});

The proper way is study the ajax callbacks and states already made into javascript/jQuery and play with them. If you need more advanced kind of feature, will need to send by backend some headers forcing some statuses that can be handled by the proper callbacks or customized ones.

You can use the HTTP status codes mainly treated with major js libraries/frameworks (even the XMLHttpRequest pure itself that follow the HTTP pattern of codes, see MDN ).

Directly answering your question, no, is not right. Your ajax is using a main callback (success) and handling by returned values. It's works, but lacks best practices about callbacks, like I mentioned above.

An example what you can do:

$("#wrapper").on("submit", "#registration-form", function(e){
        e.preventDefault();
        $.ajax({
            type: "POST",
            url: "registerProcessing.php",
            data: $("#registration-form").serialize(),
            dataType: "json",
            success: function(result){
                $("#success-message").html(result.message);
            },
            error: function(result){
               $("#error-message").html(result.message);
            }
        });
    });

or

$("#wrapper").on("submit", "#registration-form", function(e){
        e.preventDefault();
        $.ajax({
            type: "POST",
            url: "registerProcessing.php",
            data: $("#registration-form").serialize(),
            dataType: "json",
            statusCode: {
              404: function() {
                 $("#error-message").html('NOT FOUND');
              },
             200: function(result) {
                $("#success-message").html(result.message);
             },
             500: function(result) {
                $("#error-message").html(result.message);
             }
           }
        });
    });

Or with XMLHTTPREQUEST example:

var request;
if(window.XMLHttpRequest)
    request = new XMLHttpRequest();
else
    request = new ActiveXObject("Microsoft.XMLHTTP");
request.open('GET', 'http://www.mozilla.org', false);
request.send(); // there will be a 'pause' here until the response to come.
// the object request will be actually modified
switch (request.status){
   case 404:
    break;
   case 500:
    break;
   case 200;
   break
}

To add to @CarlosAlexandre's answer about handling errors using HTTP status codes: for your transition to OOP programming, you should be aware that it is becoming a best practice to use exception handling to pass error conditions around. This could like something like this:

User.php

class User{        
    //register method
    public function register($nickname, $password, $email){
        //example validation
        if($nickname==123){
            throw new InvalidArgumentException('Invalid username');
        }

        //add user to the database
        //sql code here
    }
}

registerProcessing.php

require_once 'User.php';

$user = new User();
$response = array(
    'success' => 0,
    'message' => 'Unknown error',
);

try {
    $user->register($_POST["nickname"], $_POST["password"], $_POST["email"]);

    $response['success'] = 1;
    $response['message'] = 'Registration successful.';
} catch (Exception $exception) {
    $response['message'] = $exception->getMessage();
}

echo json_encode($response);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM