如何确定REST API请求的来源

30

我有一个 RESTful API,其中的控制器应该在我的安卓应用程序访问时返回 JSON 响应,在被网络浏览器访问时返回一个“视图”。我甚至不确定我是否以正确的方式处理这个问题。我正在使用 Laravel,以下是我的控制器代码:

class TablesController extends BaseController {

    public function index()
    {
        $tables  = Table::all();

        return Response::json($tables);
    }
}

我需要类似这样的东西

class TablesController extends BaseController {

    public function index()
    {
        $tables  = Table::all();

        if(beingCalledFromWebBrowser){
            return View::make('table.index')->with('tables', $tables);
        }else{ //Android 
            return Response::json($tables);
        }
    }

看看这些回答彼此之间的差异吧?

7个回答

47

注意:此内容供未来观众参考

我发现一种方便的方法是在 API 调用中使用前缀api。在路由文件中使用:

Route::group('prefix'=>'api',function(){
    //handle requests by assigning controller methods here for example
    Route::get('posts', 'Api\Post\PostController@index');
}

在上述方法中,我为api调用和web用户分别使用控制器。但是如果您想要使用相同的控制器,那么Laravel Request有一种方便的方式。您可以在控制器内部识别前缀。

public function index(Request $request)
{
    if( $request->is('api/*')){
        //write your logic for api call
        $user = $this->getApiUser();
    }else{
        //write your logic for web call
        $user = $this->getWebUser();
    }
}

is 方法允许您验证传入的请求 URI 是否与给定模式匹配。当使用此方法时,您可以使用 * 字符作为通配符。


2
当你使用像Cloudflare这样的服务时,你的答案非常有用。因为我注意到,使用ajax进行http请求时,headers会被Cloudflare更改,而Laravel根据Accept header中的值来确定请求是否期望json。使用$request->is('api/*')代替$request->expectsJson()对我来说非常有效。 - The Stompiest

33
你可以这样使用Request::wantsJson()
if (Request::wantsJson()) {
    // return JSON-formatted response
} else {
    // return HTML response
}
基本上,Request::wantsJson() 的作用是检查请求中的 accept 标头是否为 application/json,并基于此返回 true 或 false。这意味着您需要确保您的客户端也发送了一个 "accept: application/json" 标头。

请注意,我的回答并不确定请求是否来自 REST API,而是检测客户端是否请求 JSON 响应。虽然使用 REST API 不一定需要要求 JSON 响应,但我的回答仍应该是正确的。因为 REST API 可以返回 XML、HTML 等其他类型的响应。


参考 Laravel 的 Illuminate\Http\Request

/**
 * Determine if the current request is asking for JSON in return.
 *
 * @return bool
 */
public function wantsJson()
{
    $acceptable = $this->getAcceptableContentTypes();

    return isset($acceptable[0]) && $acceptable[0] == 'application/json';
}

事实是,当我从浏览器访问API时,并不是所有的请求都使用ajax。我应该使用吗? - frankelot
好的,我已经修改了我的回答。你需要确保你的应用程序通过在请求中设置“accept”头为“application/json”来请求json。稍后会更新内部工作原理。 - Unnawut
它报错了,Request::wantsJson()不应该以静态方式调用。你必须像这样调用它:$request->wantsJson()。另外,在你的API请求头中记得添加'accept': 'application/json'。 - undefined

4
使用这种方法,您可以简单地识别URL是从Web还是API中调用的。
控制器代码
if ( Request::capture()->expectsJson()  )
     {  return "API Method";  }
     else
     {  return "Web Method";     }

路由代码

api.php中的代码: Route::post("category","CategoryController@index");

Web.php中的代码: Route::get("category","CategoryController@index");


2

您的应用程序是否使用不同的头部或授权令牌?如果是这样,您可以创建一个辅助函数来检查头部中的关键字。我们的应用程序发送Authorization头部(用于passport),而我们的Web端在Web会话中使用passport Web cookie,因此我只需要查找Authorization关键字就知道这是应用程序:

if(request()->hasHeader('Authorization')){
//is from app
}

2
您可以使用

标签


if ($request->wantsJson()) {
     // enter code heree
}

2
恭喜您复制了一个6年前被接受的答案中的两行代码。 - miken32

1
You can easily check the route that came from either web or API with this.

if($request->route()->getPrefix() === 'api') {
   // Your logic
}

1

对我来说,这些都不起作用,因为我的路由结构不同。

也可以像这样做。

public function __construct(Request $request) {
    $this->request = $request;
    $this->isApi = $this->request->segment(1) === 'api' ? true : false;
}

然后在控制器中像这样使用它。

if($this->isApi){
  //do things for api view
} else {
 //do things for html view
}

希望能有所帮助。


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