2013-06-12 32 views
6

我已閱讀cookbook中的RequestHandler部分。有isXml(),isRss()等,但沒有isJson()Cakephp - 如果請求是JSON?

任何其他方式來檢查請求是否是JSON?

所以當url是mysite.com/products/view/1.json它會給JSON數據,但沒有.json它會給HTML視圖。

感謝

回答

10

我不認爲CakePHP有像isJson()用於JSON數據的一些功能非常詳細的說明,你可以雖然創建自定義,如:

//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)) { 
... 
} 

補充: 如果您要檢查以.json EXTENS離子和相應的過程,那麼你可以在你的控制器:

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

感謝您的回答,也許我的問題有點混亂。我希望網站在URL末尾有'.json'時返回JSON數據,否則返回正常HTML視圖 – hrsetyono

+1

歡迎您.. :) –

4

你有沒有看遍了,跟着書中?:

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

+1

我不認爲我需要爲這個自定義視圖,因爲我只需要從數據庫中純查詢結果。但如果這是唯一的方法,我想我會遵循它。所以在我的'控制器',我不需要任何'if'語句,像'if(json)渲染這個'? – hrsetyono

+0

如果您想用json響應,您不需要使用自定義視圖。他們只是告訴你,你*可以*使用自定義視圖。通過使用Router :: parseExtensions('json')並在你的控制器中加載RequestHandler,你可以簡單地寫'$ this-> set('product',$ product); $ this-> set('_ serialize','product');'如果你的請求有一個'Accept:application/json'頭文件,它會自動響應json,或者如果你的請求有'Accept:text/html'。您不應該一直檢查是否('類型'),因爲可以爲您處理內容類型協商! – jbielick

4

你可以使自己的探測器。請參閱:http://book.cakephp.org/2.0/en/controllers/request-response.html#inspecting-the-request

例如,在您的AppController.php

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

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

現在你可以使用它:

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

嗨,謝謝,我會嘗試在我需要的時候使用它再次起作用。 – hrsetyono

6

CakePHP會正確處理這一點,因爲JSON是一個響應類型,而不是一個類型的請求。條款請求和響應可能會造成一些混淆。請求對象表示發送給服務器的HTTP請求的頭信息。瀏覽器通常會向服務器發送POST或GET請求,並且這些請求可以將而不是格式化爲JSON。所以對於請求來說JSON類型是不可能的。

隨着中說,該服務器可以給JSON的響應和瀏覽器可以把它支持的JSON響應請求頭。所以而不是檢查請求是什麼。檢查瀏覽器支持哪些接受的響應。

所以不是寫作$this->request->isJson()你應該寫$this->request->accepts('application/json')

此信息模糊地顯示在document here中,但is(..)文檔中沒有提及see also鏈接。很多人首先看那裏。沒有看到JSON,並假設缺少一些東西。

如果你想使用一個請求檢測檢查,如果瀏覽器支持JSON響應,那麼你可以很容易地在您的beforeFilter添加一行。

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

有這種方法相關的風險,因爲瀏覽器可以發送多個響應類型爲來自服務器的響應可能。包括所有類型的通配符。因此,這會將您限制爲只顯示支持JSON響應的請求。由於JSON是文本格式,因此對於期望使用JSON的瀏覽器,text/plain類型是有效的響應類型。

我們可以修改我們的規則以包含text/plain這樣的JSON響應。

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

這將包括text/plain的請求作爲一個JSON響應類型,但現在我們有一個問題。僅僅因爲瀏覽器支持text/plain響應並不意味着它期待JSON響應。

這就是爲什麼最好在您的URL中加入命名約定來表示JSON響應。您可以使用.json文件擴展名或/json/controller/action前綴。

我更喜歡使用URL的命名前綴。這允許您在控制器中創建json_action方法。然後你可以像這樣爲前綴創建一個檢測器。

$this->request->addDetector('json',array('callback'=>function($req){return isset($req->params['prefix']) && $req->params['prefix'] == 'json';})); 

現在探測器將始終正常工作,但我認爲它是檢測一個JSON請求不正確的用法。由於沒有這樣的東西作爲JSON請求。只有JSON響應。

+1

嗨,謝謝你的回答。它清除了我的一些困惑。 – 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

感謝您的補充。這對其他人很有用 – hrsetyono

1

非常感謝@Schlaefer先生。我閱讀你的評論並嘗試,哇現在正在工作。

//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'); 

//獲取任務的函數返回的所有任務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') 
      )); 
     } 
    }