W tej sytuacji zawsze najpierw myślę o interfejsie, a następnie piszę kod PHP, aby go obsługiwać.
- Jest to interfejs API REST, dlatego konieczne są znaczące kody stanu HTTP.
- Chcesz, aby spójne, elastyczne struktury danych były wysyłane do i od klienta.
Pomyślmy o wszystkich rzeczach, które mogą się nie udać, i ich kodach stanu HTTP:
- Serwer zgłasza błąd (500)
- Błąd uwierzytelnienia (401)
- Żądany zasób nie został znaleziony (404)
- Dane, które modyfikujesz, zostały zmienione od czasu ich załadowania (409)
- Błędy walidacji podczas zapisywania danych (422)
- Klient przekroczył wskaźnik żądań (429)
- Nieobsługiwany typ pliku (415)
Uwaga: istnieją inne, które możesz później zbadać.
W przypadku większości stanów awaryjnych zwracany jest tylko jeden komunikat o błędzie. The422 Unprocessable Entity
Odpowiedź, której użyłem do „błędów walidacji” może zwrócić więcej niż jeden błąd --- jeden lub więcej błędów na pola formularza.
Potrzebujemy elastycznej struktury danych do reagowania na błędy.
Weźmy jako przykład 500 Internal Server Error
:
HTTP/1.1 500 Internal Server Error
Content-Type: text/json
Date: Fri, 16 Jan 2015 17:44:25 GMT
... other headers omitted ...
{
"errors": {
"general": [
"Something went catastrophically wrong on the server! BWOOP! BWOOP! BWOOP!"
]
}
}
Porównaj to z prostymi błędami weryfikacji podczas próby wysłania czegoś na serwer:
HTTP/1.1 422 Unprocessable Entity
Content-Type: text/json
Date: Fri, 16 Jan 2015 17:44:25 GMT
... other headers omitted ...
{
"errors": {
"first_name": [
"is required"
],
"telephone": [
"should not exceed 12 characters",
"is not in the correct format"
]
}
}
Kluczem tutaj jest typ zawartości text/json
. Informuje to aplikacje klienckie, że mogą dekodować treść odpowiedzi za pomocą dekodera JSON. Jeśli powiedzmy, że wewnętrzny błąd serwera nie został wykryty i zamiast tego zostanie wyświetlona ogólna strona internetowa „Coś poszło nie tak”, typ zawartości powinientext/html; charset=utf-8
taki, aby aplikacje klienckie nie próbowały dekodować treści odpowiedzi jako JSON.
Wygląda to na wyszukane i eleganckie, dopóki nie będziesz musiał obsługiwać odpowiedzi JSONP . Musisz zwrócić 200 OK
odpowiedź, nawet w przypadku awarii. W takim przypadku musisz wykryć, że klient żąda odpowiedzi JSONP (zwykle wykrywając parametr żądania adresu URL o nazwiecallback
) i nieco zmienić strukturę danych:
(GET / posts / 123? Callback = displayBlogPost)
<script type="text/javascript" src="/posts/123?callback=displayBlogPost"></script>
HTTP/1.1 200 OK
Content-Type: text/javascript
Date: Fri, 16 Jan 2015 17:44:25 GMT
... other headers omitted ...
displayBlogPost({
"status": 500,
"data": {
"errors": {
"general": [
"Something went catastrophically wrong on the server! BWOOP! BWOOP! BWOOP!"
]
}
}
});
Następnie moduł obsługi odpowiedzi na kliencie (w przeglądarce internetowej) powinien mieć globalną funkcję JavaScript o nazwie, displayBlogPost
która akceptuje pojedynczy argument. Ta funkcja musiałaby ustalić, czy odpowiedź się powiodła:
function displayBlogPost(response) {
if (response.status == 500) {
alert(response.data.errors.general[0]);
}
}
Więc zadbaliśmy o klienta. Teraz zajmijmy się serwerem.
<?php
class ResponseError
{
const STATUS_INTERNAL_SERVER_ERROR = 500;
const STATUS_UNPROCESSABLE_ENTITY = 422;
private $status;
private $messages;
public function ResponseError($status, $message = null)
{
$this->status = $status;
if (isset($message)) {
$this->messages = array(
'general' => array($message)
);
} else {
$this->messages = array();
}
}
public function addMessage($key, $message)
{
if (!isset($message)) {
$message = $key;
$key = 'general';
}
if (!isset($this->messages[$key])) {
$this->messages[$key] = array();
}
$this->messages[$key][] = $message;
}
public function getMessages()
{
return $this->messages;
}
public function getStatus()
{
return $this->status;
}
}
I aby użyć tego w przypadku błędu serwera:
try {
// some code that throws an exception
}
catch (Exception $ex) {
return new ResponseError(ResponseError::STATUS_INTERNAL_SERVER_ERROR, $ex->message);
}
Lub podczas sprawdzania poprawności danych wprowadzanych przez użytkownika:
// Validate some input from the user, and it is invalid:
$response = new ResponseError(ResponseError::STATUS_UNPROCESSABLE_ENTITY);
$response->addMessage('first_name', 'is required');
$response->addMessage('telephone', 'should not exceed 12 characters');
$response->addMessage('telephone', 'is not in the correct format');
return $response;
Następnie potrzebujesz czegoś, co pobiera zwrócony obiekt odpowiedzi i przekształca go w JSON i wysyła odpowiedź w wesoły sposób.