2013-06-12 31 views
6

Tôi đã đọc phần RequestHandler trong cookbook. Có isXml(), isRss(), v.v. Nhưng không có isJson().CakePHP - Nếu yêu cầu là JSON?

Bất kỳ cách nào khác để kiểm tra xem yêu cầu có phải là JSON không?

Vì vậy, khi url là mysite.com/products/view/1.json, nó sẽ cung cấp dữ liệu JSON, nhưng không có .json nó sẽ cung cấp Chế độ xem HTML.

Cảm ơn

Trả lời

10

Tôi không nghĩ rằng CakePHP có một số chức năng như isJson() cho dữ liệu json, bạn có thể tạo tùy chỉnh của bạn, như:

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

Đã thêm: nếu bạn muốn kiểm tra .json extens ion và quá trình phù hợp, sau đó bạn có thể làm trong bộ điều khiển của mình:

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

Cảm ơn câu trả lời, có lẽ câu hỏi của tôi hơi khó hiểu. Tôi muốn trang web trả lại dữ liệu JSON khi nó có '.json' ở cuối URL, nếu không, hãy quay lại chế độ xem HTML bình thường – hrsetyono

+1

bạn được chào đón .. :) –

4

Các bạn đã nhìn qua và theo các hướng dẫn rất chi tiết trong cuốn sách ?:

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

+1

Tôi không nghĩ rằng tôi cần phải xem tùy chỉnh cho điều này kể từ khi tôi chỉ cần kết quả truy vấn tinh khiết từ cơ sở dữ liệu. Nhưng nếu đây là cách duy nhất, tôi đoán tôi sẽ theo nó. Vì vậy, trong 'điều khiển' của tôi, tôi không cần bất kỳ câu lệnh' if' nói như 'if (json) render this'? – hrsetyono

+0

Bạn không cần sử dụng chế độ xem tùy chỉnh nếu bạn muốn trả lời bằng json. Họ chỉ nói với bạn rằng bạn * có thể * sử dụng chế độ xem tùy chỉnh. Bằng cách sử dụng Router :: parseExtensions ('json') và tải RequestHandler trong bộ điều khiển của bạn, bạn có thể chỉ cần viết '$ this-> set ('product', $ product); $ this-> set ('_ serialize', 'product'); 'và nó sẽ tự động trả lời với json nếu yêu cầu của bạn có tiêu đề' Accept: application/json' hoặc hiển thị tệp xem nếu yêu cầu của bạn có 'Accept: text/html'. Bạn không nên kiểm tra ('loại') tất cả các thời gian vì đàm phán loại nội dung có thể được xử lý cho bạn! – jbielick

4

Bạn có thể tự tạo thiết bị dò tìm riêng. Xem: http://book.cakephp.org/2.0/en/controllers/request-response.html#inspecting-the-request

Ví dụ trong AppController.php bạn

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

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

Bây giờ bạn có thể sử dụng nó:

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

Xin chào Cảm ơn, tôi sẽ cố gắng sử dụng khi tôi cần một lần nữa. – hrsetyono

6

CakePHP là xử lý này một cách chính xác, bởi vì JSON là một loại phản ứng và không phải là một loại yêu cầu. Yêu cầu và phản hồi của các điều khoản có thể gây ra một số khó hiểu. Đối tượng yêu cầu thể hiện thông tin tiêu đề của yêu cầu HTTP được gửi đến máy chủ. Trình duyệt thường gửi yêu cầu POST hoặc GET tới máy chủ và các yêu cầu đó có thể không phải được định dạng là JSON. Vì vậy, nó không thể cho một yêu cầu được loại JSON.

Với điều đó đã nói, máy chủ có thể trả lời JSON và trình duyệt có thể đặt vào tiêu đề yêu cầu hỗ trợ phản hồi JSON. Vì vậy, thay vì kiểm tra xem yêu cầu là gì. Kiểm tra những phản hồi được chấp nhận được hỗ trợ bởi trình duyệt.

Vì vậy, thay vì viết $this->request->isJson() bạn nên viết $this->request->accepts('application/json').

Thông tin này được hiển thị mơ hồ trong document here, nhưng không có tham chiếu see also liên kết trong tài liệu is(..). Vì vậy, nhiều người nhìn có đầu tiên. Không thấy JSON và giả sử một cái gì đó bị thiếu.

Nếu bạn muốn sử dụng bộ dò tìm yêu cầu để kiểm tra xem trình duyệt có hỗ trợ phản hồi JSON hay không, thì bạn có thể dễ dàng thêm một lớp lót vào bộ lọc trước của mình.

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

Có rủi ro liên quan đến phương pháp này, bởi vì trình duyệt có thể gửi nhiều loại phản hồi dưới dạng phản hồi có thể từ máy chủ. Bao gồm ký tự đại diện cho tất cả các loại. Vì vậy, điều này giới hạn bạn chỉ yêu cầu chỉ ra một phản ứng JSON được hỗ trợ.Vì JSON là định dạng văn bản, kiểu text/plain là loại phản hồi hợp lệ cho trình duyệt mong đợi JSON.

Chúng tôi có thể sửa đổi quy tắc của chúng tôi để bao gồm text/plain cho các phản hồi JSON như thế này.

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

Điều đó sẽ bao gồm yêu cầu văn bản/đơn giản làm loại phản hồi JSON, nhưng giờ chúng tôi gặp sự cố. Chỉ vì trình duyệt hỗ trợ trả lời văn bản/đồng bằng không có nghĩa là nó đang mong đợi một phản hồi JSON.

Đây là lý do tại sao nên kết hợp quy ước đặt tên vào URL của bạn để biểu thị phản hồi JSON. Bạn có thể sử dụng tiện ích mở rộng tệp .json hoặc tiền tố /json/controller/action.

Tôi thích sử dụng tiền tố được đặt tên cho URL. Điều đó cho phép bạn tạo các phương thức json_action trong bộ điều khiển của mình. Sau đó, bạn có thể tạo bộ dò tìm cho tiền tố như thế này.

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

Trình phát hiện sẽ luôn hoạt động chính xác, nhưng tôi cho rằng đó là việc sử dụng không chính xác phát hiện yêu cầu JSON. Vì không có thứ gì như một yêu cầu JSON. Chỉ trả lời JSON.

+1

Xin cảm ơn câu trả lời. Nó xóa một số nhầm lẫn tôi đã có. – 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

Cảm ơn bạn đã thêm. Điều này sẽ hữu ích cho người khác – hrsetyono

1

Cảm ơn rất nhiều Mr @Schlaefer. Tôi đọc bình luận của bạn và thử, Wow nó đang làm việc ngay bây giờ.

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

// Nhận nhiệm vụ chức năng trả lại tất cả công việc ở định dạng 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') 
      )); 
     } 
    } 
Các vấn đề liên quan