如何在Yii中以JSON格式(application/json)获取响应?

55

如何在Yii框架中以JSON格式(application/json)获取响应?

9个回答

97

Yii 1:

在您的(基础)控制器中创建此函数:

/**
 * Return data to browser as JSON and end application.
 * @param array $data
 */
protected function renderJSON($data)
{
    header('Content-type: application/json');
    echo CJSON::encode($data);

    foreach (Yii::app()->log->routes as $route) {
        if($route instanceof CWebLogRoute) {
            $route->enabled = false; // disable any weblogroutes
        }
    }
    Yii::app()->end();
}

然后在你的操作结束时简单地调用:

$this->renderJSON($yourData);

对于 Yii 2:

Yii 2 已经内置了此功能,在您的控制器操作的末尾使用以下代码即可:

Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
return $data;

我注意到设置 header()Yii::app()->end(); 没有任何区别。在 Chrome 开发者工具中,如果你查看 Header 标签下的 Response Header,它们都会给出相同的 Content-Length。如果 AJAX 是以“json”格式输出预期的输出,则即使发送了 HTML,浏览器/jQuery 也将该响应视为 json 并且似乎在所有现代浏览器中都能正常工作。虽然我不否认设置 header() 是好事。 - mohitp
与其禁用Web日志路由,这种方法将更加健壮(尚未测试):ob_start(); Yii::app()->end(0, false); ob_end_clean(); exit(0); - marcovtwout

20

Yii2控制器内部的代码:

public function actionSomeAjax() {
    $returnData = ['someData' => 'I am data', 'someAnotherData' => 'I am another data'];

    $response = Yii::$app->response;
    $response->format = \yii\web\Response::FORMAT_JSON;
    $response->data = $returnData;

    return $response;
}

2
这应该是被采纳的答案。+1 遵循 Yii 的 api。 - Gogol
谢谢您先生!^-^ - Jeancarlo Fontalvo

19
$this->layout=false;
header('Content-type: application/json');
echo CJavaScript::jsonEncode($arr);
Yii::app()->end(); 

在调用Yii::app()->end()之前,不要忘记禁用WebLogRoutes,否则调试信息可能会附加到您的JSON中,并潜在地使其无效。 - marcovtwout
我非常确定end()会关闭日志记录,这就是为什么我在这里添加它的原因。 - Neil McGuigan
1
它不会结束(): "终止应用程序。该方法通过在退出之前调用onEndRequest来替换PHP的exit()函数。" 在CLogRouter(http://www.yiiframework.com/doc/api/1.1/CLogRouter#processLogs-detail)中: "该方法是CApplication::onEndRequest事件的事件处理程序。" - marcovtwout
@marcovtwout,是的,你说得对。我想到了exit(),它会在Yii之前结束应用程序,因此没有日志。 - Neil McGuigan

10
$this->layout=false;
header('Content-type: application/json');
echo json_encode($arr);
Yii::app()->end(); 

4
一些小改动:对于模型使用CJSON::encode();不需要执行$this->layout=false,因为Yii::app()->end()会终止应用程序而不输出布局。 - Ethan
我认为最好将最佳答案更改为@marcovtwout。 - Marcio Mazzucato

5
class JsonController extends CController {

    protected $jsonData;

    protected function beforeAction($action) {
        ob_clean(); // clear output buffer to avoid rendering anything else
        header('Content-type: application/json'); // set content type header as json
        return parent::beforeAction($action);
    }

    protected function afterAction($action) {
        parent::afterAction($action);
        exit(json_encode($this->jsonData)); // exit with rendering json data
    }

}

class ApiController extends JsonController {

    public function actionIndex() {
        $this->jsonData = array('test');
    }

}

1
一种更简单的方法是使用


echo CJSON::encode($result);

示例代码:

public function actionSearch(){
    if (Yii::app()->request->isAjaxRequest && isset($_POST['term'])) {
            $models = Model::model()->searchNames($_POST['term']);
            $result = array();
            foreach($models as $m){
                $result[] = array(
                        'name' => $m->name,
                        'id' => $m->id,
                );


            }
            echo CJSON::encode($result);
        }
}

cheers :)


1

对于Yii2,使用这个简单易记的选项

Yii::$app->response->format = "json";
return $data

0
在你想要呈现 JSON 数据的控制器操作中,例如:actionJson()。
public function actionJson(){
    $this->layout=false;
    header('Content-type: application/json');
    echo CJSON::encode($data);
    Yii::app()->end(); // equal to die() or exit() function
}

查看更多Yii API


-1
Yii::app()->end()

我认为这种解决方案不是结束应用程序流程的最佳方式,因为它使用 PHP 的 exit() 函数,这意味着立即退出执行流程。是的,有 Yii 的 onEndRequest 处理程序和 PHP 的 register_shutdown_function,但仍然过于宿命论。

对我来说,更好的方式是这样的

public function run($actionID) 
{
    try
    {
        return parent::run($actionID);
    }
    catch(FinishOutputException $e)
    {
        return;
    }
}

public function actionHello()
{
    $this->layout=false;
    header('Content-type: application/json');
    echo CJavaScript::jsonEncode($arr);
    throw new FinishOutputException;
}

所以,即使在执行之后,应用程序流程仍然继续执行。

如果您已经设置了layout=false,那么一个简单的“return”就可以了吗?甚至可以省略。我看不出来为什么要尝试捕获并创建自定义异常。 - marcovtwout
1
这太糟糕了。抛出异常以输出响应。 - grantwparks
现在,经过一段时间的思考,我完全同意使用异常来管理控制器/表示逻辑是错误的。 - Mihailoff

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接