如何从Laravel中的相同控制器方法返回不同的输出格式?

时间:2017-03-15 16:13:58

标签: php json laravel laravel-5

我想设置正确的路线和型号,所以当我访问www.myapp.com/search?keyword=test时,我会看到数据视图,当我访问api.myapp.com/search?keyword=test时获得完全相同的搜索结果的JSON表示。

如果我像这样整理子域路由:

Route::group(array('domain' => '{subdomain}.myapp.com'), function()
{
    Route::get('/', function($subdomain)
    {
        dd($subdomain);
    });
});

使用相同模型方法的最简单方法是什么,而不是使用模型对象数组返回视图(对于非子域路由),如下所示:

return view('search', compact('models'));

我返回一个JSON对象数组,就像这样:

return $models;

注意:子域名不是必需的,也可以是myapp.com/api/search?keyword=test

感谢。

2 个答案:

答案 0 :(得分:0)

有几种方法可以做到这一点。

一种选择是根本不使用单独的子域或路径。而是使用内置机制来检查请求的Content-Type标头中的Accept

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SearchController extends Controller
{
    public function getSearch(Request $req)
    {
        $keyword = $req->input('keyword');

        $results = yourCodeThatDoesTheSearch();

        // If the request has header `Accept: */json`, return JSON
        if ($req->wantsJson())
        {
            return $results;
        }

        // Otherwise, return view
        return view('search', compact('results'));
    }
}

但是,您可能仍希望使用子域,因为您无法控制请求标头,或者您希望能够轻松指示您将获得哪些响应。

这是使用子域执行此操作的最简单方法:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SearchController extends Controller
{
    public function getSearch(Request $req)
    {
        $keyword = $req->input('keyword');

        $results = yourCodeThatDoesTheSearch();

        // If the request came to the API subdomain, return JSON
        if ($req->route('subdomain') === 'api')
        {
            return $results;
        }

        // Otherwise, return view
        return view('search', compact('results'));
    }
}

但是,如果您打算在代码中的许多地方执行此操作,则应避免在任何地方重复使用相同的if语句。

相反,创建一个辅助函数:

<?php

use Illuminate\Contracts\Routing\ResponseFactory;

if (! function_exists('response_auto')) {
    function response_auto($view, $data, $request, $status = 200, array $headers = [])
    {
        $factory = app(ResponseFactory::class);

        if ($request->wantsJson())
        {
            return $factory->json($data, $status, $headers);
        }


        return $factory->view($view, compact('data'), $status, $headers);
    }
}

然后您可以在控制器中使用它,如下所示:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SearchController extends Controller
{
    public function getSearch(Request $req)
    {
        $keyword = $req->input('keyword');

        $results = yourCodeThatDoesTheSearch();

        return response_auto('search', $results, $req);
    }
}

答案 1 :(得分:0)

添加到Moshe Katz的答案。如果您只是在控制器中执行$req->wantsJson(),则可以正常工作。但是,在某些情况下,如果用户点击后退按钮,json将由于缓存而在视图中返回。一个健壮的api将在它自己的控制器中,并使用存储库进行数据库查询。这可能有点矫枉过正。

另一种选择是在您的网址中使用查询参数。

实施例: 在您的ajax客户端(axios)

axios.get('/stuff', {params: {json: true}).then(response => return response); 

这将向

发送请求
/stuff?json=true
laravel控制器中的

(StuffController @ index)

public function index(Request $request) 
{ 
    $stuff = Stuff::all();

    if ($request->query('json')) { 
        return $stuff; 
    }

    return view('stuff.index', compact('stuff'));
}

这使您可以轻松识别请求是否需要json,防止因浏览器缓存而导致的不必要的返回,并将代码保存在同一个控制器中。