2013-06-12 18 views
6

Przeczytałem część RequestHandler w cookbook. Istnieją isXml(), isRss() itd. Ale nie ma isJson().Cakephp - Jeśli Żądanie jest JSON?

Każdy inny sposób sprawdzenia, czy żądanie to JSON?

Kiedy adres URL to mysite.com/products/view/1.json, otrzymasz dane JSON, ale bez numeru .json otrzymasz widok HTML.

Dzięki

Odpowiedz

10

nie sądzę CakePHP ma jakąś funkcję jak isJson() dla danych JSON, można stworzyć swój zwyczaj chociaż, jak:

//may be in your app controller 
function isJson($data) { 
    return (json_decode($data) != NULL) ? true : false; 
} 
//and you can use it in your controller 
if($this->isJson($your_request_data)) { 
... 
} 

Dodano: jeśli chcesz sprawdzić .json EXTENS jon i odpowiednio przetwarzaj, możesz to zrobić w kontrolerze:

$this->request->params['ext']; //which would give you 'json' if you have .json extension 
+0

Dzięki za odpowiedź, może moje pytanie jest nieco mylące. Chcę, aby strona zwróciła dane JSON, gdy ma '.json' na końcu adresu URL, w przeciwnym razie zwróci normalny widok HTML – hrsetyono

+1

jesteś mile widziany .. :) –

4

Czy przejrzałem i po bardzo szczegółowe instrukcje w książce ?:

http://book.cakephp.org/2.0/en/views/json-and-xml-views.html

+1

Nie sądzę, muszę niestandardowy pogląd na to, odkąd wystarczy czysty wynik zapytania z bazy danych. Ale jeśli to jedyny sposób, myślę, że pójdę za tym. Więc w moim 'kontroler', nie potrzebuję żadnego' if' oświadczenia, mówiąc jak 'if (json) renderować to'? – hrsetyono

+0

Nie musisz używać niestandardowego widoku, jeśli chcesz odpowiedzieć jsonem. Mówią ci tylko, że możesz * używać * niestandardowego widoku. Używając Router :: parseExtensions ('json') i ładując RequestHandler do kontrolera, możesz po prostu napisać '$ this-> set ('product', $ product); $ this-> set ('_ serialize', 'product'); 'i automagicznie odpowie z jsonem, jeśli twoja prośba ma nagłówek' Accept: application/json' lub wyrenderuj plik widoku, jeśli twoja prośba zawiera 'Accept: text/html'. Nie powinieneś ciągle sprawdzać ("typ"), ponieważ negocjacja typu zawartości może być dla ciebie obsługiwana! – jbielick

4

Możesz tworzyć własne detektory. Zobacz: http://book.cakephp.org/2.0/en/controllers/request-response.html#inspecting-the-request

na przykład w swojej AppController.php

public function beforeFilter() { 
    $this->request->addDetector(
    'json', 
    [ 
     'callback' => [$this, 'isJson'] 
    ] 
); 
    parent::beforeFilter(); 
} 

public function isJson() { 
    return $this->response->type() === 'application/json'; 
} 

Teraz można go używać:

$this->request->is('json'); // or 
$this->request->isJson(); 
+0

Cześć Dzięki, spróbuję użyć tego, kiedy tego potrzebuję ponownie działać. – hrsetyono

6

CakePHP jest obsługa to prawidłowo, ponieważ JSON jest rodzajem odpowiedzi a nie typu wniosku. Warunki żądania i odpowiedzi mogą powodować pewne zamieszanie. Obiekt żądania reprezentuje informacje o nagłówku żądania HTTP wysłanego na serwer. Przeglądarka zazwyczaj wysyła żądania POST lub GET do serwera, a te żądania mogą być , a nie sformatowane jako JSON. Tak więc nie jest możliwe, aby wniosek był typu JSON.

Po tym, serwer może dać odpowiedź JSON i przeglądarka może umieścić w nagłówku żądania, że ​​obsługuje odpowiedź JSON. Więc zamiast sprawdzać, co było prośbą. Sprawdź, jakie zaakceptowane odpowiedzi są obsługiwane przez przeglądarkę.

Zamiast więc pisać $this->request->isJson() powinieneś napisać: $this->request->accepts('application/json').

Ta informacja jest niejednoznacznie wyświetlana w document here, ale nie ma odnośników see also w dokumentacji see also. Tak wielu ludzi najpierw tam patrzy. Nie widzisz JSON i zakładam, że czegoś brakuje.

Jeśli chcesz użyć detektora żądań w celu sprawdzenia, czy przeglądarka obsługuje odpowiedź JSON, możesz z łatwością dodać jedną linijkę do swojego filtru beforeFilter.

$this->request->addDetector('json',array('callback'=>function($req){return $req->accepts('application/json');})); 

Istnieje ryzyko związane z tym podejściem, ponieważ przeglądarka może wysłać wiele odpowiedzi jako możliwą odpowiedź z serwera. W tym symbol wieloznaczny dla wszystkich typów. Ogranicza to zatem tylko żądania, które wskazują, że odpowiedź JSON jest obsługiwana.Ponieważ JSON jest formatem tekstowym, typ text/plain jest poprawnym typem odpowiedzi dla przeglądarki oczekującej JSON.

Możemy zmodyfikować naszą regułę, dodając text/plain dla takich odpowiedzi JSON.

$this->request->addDetector('json',array('callback'=>function($req){ 
    return $req->accepts('application/json') || $req->accepts('text/plain'); 
})); 

Który zawiera żądania tekst/zwykły jako typ odpowiedzi JSON, ale teraz mamy problem. To, że przeglądarka obsługuje odpowiedź tekstową/zwykłą, nie oznacza, że ​​oczekuje odpowiedzi JSON.

Dlatego lepiej wprowadzić do adresu URL konwencję nazewnictwa, aby wskazać odpowiedź JSON. Możesz użyć rozszerzenia pliku .json lub prefiksu /json/controller/action.

Wolę używać nazwanego prefiksu dla adresów URL. To pozwala na tworzenie metod json_action w kontrolerze. Następnie możesz utworzyć wykrywacz dla takiego prefiksu.

Teraz detektor będzie działał poprawnie, ale twierdzę, że jest to nieprawidłowe użycie wykrycia żądania JSON. Ponieważ nie ma czegoś takiego jak żądanie JSON. Tylko odpowiedzi JSON.

+1

Cześć dzięki za odpowiedź. Usuwa pewne zamieszanie, które miałem. – hrsetyono

1
class TestController extends Controller { 

    public $autoRender = false; 

    public function beforeFilter() { 
     $this->request->addDetector('json', array('env' => 'CONTENT_TYPE', 'pattern' => '/application\/json/i')); 
     parent::beforeFilter(); 
    } 

    public function index() { 
     App::uses('HttpSocket', 'Network/Http'); 

     $url = 'http://localhost/myapp/test/json'; 
     $json = json_encode(
      array('foo' => 'bar'), 
      JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP 
     ); 
     $options = array('header' => array('Content-Type' => 'application/json')); 

     $request = new HttpSocket(); 
     $body = $request->post($url, $json, $options)->body; 

     $this->response->body($body); 
    } 

    public function json() { 

     if ($this->request->isJson()) { 
      $data = $this->request->input('json_decode'); 
      $value = property_exists($data, 'foo') ? $data->foo : ''; 
     } 

     $body = (isset($value) && $value === 'bar') ? 'ok' : 'fail'; 
     $this->response->body($body); 
    } 
} 
+0

Dzięki za dodanie. Będzie to przydatne dla innych – hrsetyono

1

Wielkie dzięki, panie @Schlaefer. Czytam twój komentarz i próbuję, Wow, to działa.

//AppController.php 

function beforeFilter() { 
     $this->request->addDetector(
       'json', [ 
      'callback' => [$this, 'isJson'] 
       ] 
     ); 
     parent::beforeFilter(); 
     ... 
    } 


public function isJson() { 
     return $this->response->type() === 'application/json'; 
    } 
//TasksController.php 

public $components = array('Paginator', 'Flash', Session','RequestHandler'); 

// Pobierz funkcja zadania przywrócić wszystkie zadania w formacie JSON

public function getTasks() { 
     $limit = 20; 
     $conditions = array(); 
     if (!empty($this->request->query['status'])) { 
      $conditions = ['Task.status' => $this->request->query['status']]; 
     } 
     if (!empty($this->request->query['limit'])) { 
      $limit = $this->request->query['limit']; 
     } 
     $this->Paginator->settings = array('limit' => $limit, 'conditions' => $conditions); 

     $tasks = $this->paginate(); 

     if ($this->request->isJson()) { 

      $this->set(
array(
       'tasks' => $tasks, 
       '_serialize' => array('tasks') 
      )); 
     } 
    } 
Powiązane problemy