Khi tôi xử lý AJAX, mà tôi trả về dưới dạng JSON, một mẹo tôi sử dụng là tận dụng bộ đệm đầu ra. Bạn không thể chỉ lặp lại hoặc xuất bất kỳ thứ gì bạn muốn vì nó sẽ làm rối tung dữ liệu JSON, vì vậy, chẳng hạn,
ob_start(); //turn on buffering at beginning of script.
.... other code ...
print_r($somevar);
.... other code ...
$debug = ob_get_clean(); //put output in a var
$data['debug'] = $debug;
header('Content-Type: application/json');
echo json_encode($data); //echo JSON data.
Điều này có tác dụng gì, là gói bất kỳ đầu ra nào từ tập lệnh của bạn vào dữ liệu JSON của bạn để định dạng của nó không bị rối.
Sau đó, về phía javascript, bạn có thể sử dụng console.log
$.post(url, input, function(data){
if(data.debug) console.log(data.debug);
});
Nếu bạn không quen gỡ lỗi bằng console.log()
, bạn thường có thể nhấn F12
và mở trình gỡ lỗi trong hầu hết các trình duyệt. Sau đó, trong đó đầu ra sẽ được gửi đến "bàn điều khiển". IE9 gặp một chút sự cố với console.log()
nếu tôi nhớ lại, nhưng tôi không muốn đi quá xa.
LƯU Ý: Chỉ cần đảm bảo không để lại nội dung này trong mã khi bạn chuyển nó sang sản xuất, rất đơn giản chỉ cần ghi chú dòng này ra,
//$data['debug'] = $debug;
Và sau đó thông tin gỡ lỗi của bạn sẽ không được tiết lộ trong quá trình sản xuất. Có nhiều cách khác để tự động thực hiện việc này, nhưng nó phụ thuộc vào việc bạn có phát triển cục bộ rồi xuất bản lên máy chủ hay không. Ví dụ:bạn có thể chuyển nó trên $_SERVER['SERVER_ADDR'];
sẽ là ::1
hoặc 127.0.0.1
khi nó ở địa phương. Điều này có một vài hạn chế, chủ yếu là địa chỉ máy chủ không có sẵn từ Giao diện Dòng lệnh (CLI). Vì vậy, thông thường tôi sẽ gắn nó vào một hằng số chung cho biết trang web đang ở "chế độ" nào (bao gồm trong điểm vào chung, thường là index.php).
if(!defined('ENV_DEVELOPMENT')) define('ENV_DEVELOPMENT','DEVELOPMENT');
if(!defined('ENV_PRODUCTION')) define('ENV_PRODUCTION','PRODUCTION');
if(!defined('ENVIRONMENT')) define('ENVIRONMENT',ENV_DEVELOPMENT);
//site is in Development mode, uncomment for production
//if(!defined('ENVIRONMENT')) define('ENVIRONMENT',ENV_DEVELOPMENT);
Sau đó, nó là một vấn đề đơn giản để kiểm tra nó:
if(ENVIRONMENT == ENV_PRODUCTION ) $data['debug'] = $debug;
Nếu bạn biết cách sử dụng báo cáo lỗi, bạn thậm chí có thể liên kết với điều đó bằng cách sử dụng
if(ini_get('display_errors') == 1) $data['debug'] = $debug;
Điều này sẽ chỉ hiển thị gỡ lỗi khi lỗi hiển thị được bật.
Hy vọng điều đó sẽ hữu ích.
CẬP NHẬT
Bởi vì tôi đã đề cập đến nó trong các nhận xét, đây là một ví dụ về nó được bao bọc trong một lớp (đây là phiên bản đơn giản hóa, vì vậy tôi đã không kiểm tra điều này)
class LibAjax{
public static function respond($callback, $options=0, $depth=32){
$result = ['userdata' => [
'debug' => false,
'error' => false
]];
ob_start();
try{
if(!is_callable($callback)){
//I have better exception in mine, this is just more portable
throw new Exception('Callback is not callable');
}
$callback($result);
}catch(\Exception $e){
//example 'Exception[code:401]'
$result['userdata']['error'] = get_class($e).'[code:'.$e->getCode().']';
//if(ENVIRONMENT == ENV_DEVELOPMENT){
//prevents leaking data in production
$result['userdata']['error'] .= ' '.$e->getMessage();
$result['userdata']['error'] .= PHP_EOL.$e->getTraceAsString();
//}
}
$debug = '';
for($i=0; $i < ob_get_level(); $i++){
//clear any nested output buffers
$debug .= ob_get_clean();
}
//if(ENVIRONMENT == ENV_DEVELPMENT){
//prevents leaking data in production
$result['userdata']['debug'] = $debug;
//}
header('Content-Type: application/json');
echo self::jsonEncode($result, $options, $depth);
}
public static function jsonEncode($result, $options=0, $depth=32){
$json = json_encode($result, $options, $depth);
if(JSON_ERROR_NONE !== json_last_error()){
//debug is not passed in this case, because you cannot be sure that, that was not what caused the error. Such as non-valid UTF-8 in the debug string, depth limit, etc...
$json = json_encode(['userdata' => [
'debug' => false,
'error' => json_last_error_msg()
]],$options);
}
return $json;
}
}
Sau đó, khi bạn thực hiện một phản hồi AJAX, bạn chỉ cần kết thúc nó như thế này (lưu ý $ result được chuyển qua tham chiếu, theo cách này, chúng tôi không phải thực hiện trả lại và trong trường hợp ngoại lệ, chúng tôi cập nhật $ result trong "thời gian thực" thay thế khi hoàn thành)
LibAjax::respond( function(&$result){
$result['data'] = 'foo';
});
Nếu bạn cần chuyển dữ liệu bổ sung vào phần đóng, đừng quên bạn có thể sử dụng use
tuyên bố, như thế này.
$otherdata = 'bar';
LibAjax::respond( function(&$result) use($otherdata){
$result['data'][] = 'foo';
$result['data'][] = $otherdata;
});
Thao tác này xử lý việc bắt bất kỳ đầu ra nào và đưa nó vào gỡ lỗi, nếu môi trường là chính xác (đã nhận xét ra). Xin vui lòng đảm bảo thực hiện một số loại bảo vệ để đầu ra không được gửi cho khách hàng khi sản xuất, tôi không thể nhấn mạnh điều đó là đủ. Nó cũng bắt bất kỳ trường hợp ngoại lệ nào gây ra lỗi. Và nó cũng xử lý tiêu đề và mã hóa.
Một lợi ích lớn của việc này là cấu trúc nhất quán đối với JSON của bạn, bạn sẽ biết (ở phía máy khách) rằng if if(data.userdata.error)
thì bạn có một ngoại lệ ở mặt sau. Nó cung cấp cho bạn một nơi để tinh chỉnh tiêu đề của bạn, mã hóa JSON, v.v ...
Một lưu ý trong PHP7 là bạn sẽ phải hoặc nên thêm giao diện Throwable (thay vì Exception). Nếu bạn muốn bắt các lớp Lỗi và Ngoại lệ Hoặc thực hiện hai khối bắt.
Hãy chỉ nói rằng tôi làm rất nhiều AJAX và phát ngán với việc viết lại điều này mọi lúc, lớp học thực sự của tôi rộng hơn thế này, nhưng đó là ý chính của nó.
Chúc mừng.
CẬP NHẬT1
Điều này thường là do bạn không chuyển lại tiêu đề chính xác cho trình duyệt. Nếu bạn gửi (ngay trước khi gọi json_encode)
header('Content-Type: application/json');
Điều này chỉ cho phép trình duyệt biết loại dữ liệu mà nó đang lấy lại. Một điều mà hầu hết mọi người đều quên là trên web, tất cả các câu trả lời đều được thực hiện bằng văn bản. Ngay cả hình ảnh hoặc tải xuống tệp và các trang web. Tất cả chỉ là văn bản, điều làm cho văn bản đó trở nên đặc biệt là Content-Type
mà trình duyệt nghĩ rằng đó là.
Một điều cần lưu ý về header
là bạn không thể xuất bất kỳ thứ gì trước khi gửi tiêu đề. Tuy nhiên, điều này hoạt động tốt với mã tôi đã đăng vì mã đó sẽ nắm bắt tất cả đầu ra và gửi nó sau khi tiêu đề được gửi.
Tôi đã cập nhật mã gốc để có tiêu đề, tôi đã có nó trong lớp phức tạp hơn mà tôi đã đăng sau này. Nhưng nếu bạn thêm điều đó vào thì sẽ loại bỏ sự cần thiết phải phân tích cú pháp thủ công JSON.
Một điều cuối cùng mà tôi nên đề cập đến là kiểm tra xem tôi có nhận lại được JSON hay văn bản hay không, bạn vẫn có thể nhận được văn bản trong trường hợp có lỗi nào đó xảy ra trước khi bộ đệm đầu ra được bắt đầu.
Có 2 cách để thực hiện việc này.
Nếu Dữ liệu là một chuỗi cần được phân tích cú pháp
$.post(url, {}, function(data){
if( typeof data == 'string'){
try{
data = $.parseJSON(data);
}catch(err){
data = {userdata : {error : data}};
}
}
if(data.userdata){
if( data.userdata.error){
//...etc.
}
}
//....
}
Hoặc nếu bạn có tiêu đề và tiêu đề luôn là JSON, thì tiêu đề đó đơn giản hơn một chút
$.post(url, {}, function(data){
if( typeof data == 'string'){
data = {userdata : {error : data}};
}
if(data.userdata){
if( data.userdata.error){
//...etc.
}
}
//....
}
Hy vọng điều đó sẽ hữu ích!
CẬP NHẬT2
Vì chủ đề này xuất hiện nhiều nên tôi đã đặt phiên bản sửa đổi của đoạn mã trên trên GitHub của mình, bạn có thể tìm thấy nó ở đây.
https://github.com/ArtisticPhoenix/MISC/blob/master /AjaxWrapper/AjaxWrapper.php