用CodeIgniter框架搭建RESTful服务写API接口详解-HXC博客
  •  首页
  •  游戏/动漫
  •  日记/生活
  •  时间轴
  •  留言板
  • 
    用CodeIgniter框架搭建RESTful服务写API接口详解
     作者:胡新春  发布时间:2017-10-08 15:22:14  访客:210

    前言:

    CodeIgniter是php中目前优秀的框架之一,功能十分强大,但我们往往会忽视它在webservice方面的一些强大功能。在本文中,将会介绍如何使用CodeIgniter框架,为你的web应用程序建立RESTful API服务,并演示如何让创建的API和其他RESTful风格的webservices,比如Facebook或者Twitter进行交互。


    第一部分 搭建RESTful服务

    步骤1 下载并设置DEMO(如下是以较早版本讲解,较新版本文件结构有小变化)

    我们提供了相关的基础框架示例程序下载,以方便本文的接下来的讨论。

    下载地址在:https://github.com/philsturgeon/codeigniter-restserver

    较早版本下载:https://github.com/chriskacerguis/codeigniter-restserver/releases

    如下图,只需要点download sources即可:

    1505270575836560.png

    下载后,解压打开后,你会发现示例程序中已经整合好codeigniter(2.8.0版本及以前整合了完整版ci框架,从3.0版本开始为非完整版)

    为了让其运行起来,我们修改application/config/config.php文件,设置好base_url为当前应用的虚拟目录,比如我们把示例程序命名为resetserver,则config.php文件(ci框架的部署及配置可参考官网文档:https://codeigniter.org.cn/)设置为如下图所示:

    set-base-url.png

    步骤2 分析URL

    接下来,我们来分析一下在示例程序中的example_api控制器中的一些URL,结合RESTful讲解其含义,首先在浏览器中,运行http://localhost/restserver,将会看到如下界面:

    QQ截图20170913111512.png

    这里有五个示例,其中每个示例的链接都是以RESETful的形式给出的,下面我们分析其含义。注意这些都是由application/controller/example_api.php这个控制器产生的,我们分析下这些相关的URL,如下图:

    url-disect-1.png

    其中,可以看到这种形式很象CodeIgniter中的MVC架构的链接,但要注意到,传统的CodeIgniter中的有点不同,在链接的最后一部分,我们称为Resource资源。有一点RESTful知识的朋友可能知道,在RESTful中,把要操作的对象都叫资源,而且对资源是通过HTTP方式进行相关操作,比如增加,删除,编辑和查询。我们来进一步看下图的链接结构,如图:

    url-disect-2.png

    这里,进一步列出了请求URL的格式,跟着Resource后的是参数名以及其值,还有就是返回数据的显示格式,上图是指定了用json的格式返回。比如下图指定了三类返回的数据格式:

    output-examples.png

    由于我们这里要把要提供的服务设计成RESETful的webservices方式供用户调用,所以这里我们设计了多种数据结果集返回的形式,有XML,JSON,HTML,CSV等方式。

    步骤3 分析example_api.php文件

    (注意,较新版本\application\controllers\api\Example.php文件)

    接下来,我们打开application/controllers/example_api.php(注意,较新版本\application\controllers\api\Example.php文件)文件,仔细分析其代码。

    首先,在CodeIgniter中,我们要继承CodeIgniter框架本身的REST_Controller.php(这个文件位于libraries目录中),如下所示:

    <?
    require(APPPATH'.libraries/REST_Controller.php');
    class Example_api extends REST_Controller { }
    ?>

    接着我们看其中两个获得资源的方法,分别是user_get()和users_get(),其中user_get()是根据用户id去获得某个用户的信息,而users_get()则获得多个用户的信息,代码框架如下:

    <?
    require(APPPATH'.libraries/REST_Controller.php');
    
    class Example_api extends REST_Controller {
    
        function user_get()
        {
            // 获得一个用户的信息
        }
    
        function users_get()
        {
            //获得多个用户的信息
        }
    }
    
    ?>

    接着我们复习下在RESTful架构中的四类关于资源的操作。

    GET:使用GET去获得一个已经存在的资源的信息。通常我们在浏览器中输入url其实即发出了一个GET的请求。

    POST:使用POST去更新一个已经存在的资源。比如表单中的提交数据行为,都属于POST类型。

    PUT:使用HTTP的报文头的PUT,可以去新建一种资源,目前不是所有浏览器支持,所以本文不作讨论。

    DELETE:使用DELETE去删除一种资源,同样目前不是所有浏览器都支持。

    现在我们可以根据四种HTTP RESTful语义去形成如下框架:

    <?
    require(APPPATH'.libraries/REST_Controller.php');
    
    class Example_api extends REST_Controller {
    
        function user_get()
        {
        // 获得一个用户的信息
        }
    
        function user_put()
        {
            // 创建一个新用户
        }
    
        function user_post()
        {
            //更新用户信息
        }
    
        function user_delete()
        {
            //删除用户信息
        }
    }
    ?>

    接下来我们充分利用CodeIgniter框架自身的REST_Controller的优势,完善为如下代码:

    <?
    require(APPPATH'.libraries/REST_Controller.php');
    
    class Example_api extends REST_Controller {
    
        function user_get()
        {
            $data = array('returned: '. $this->get('id'));
            $this->response($data);
        }
    
        function user_post()
        {
            $data = array('returned: '. $this->post('id'));
            $this->response($data);
        }
    
        function user_put()
        {
            $data = array('returned: '. $this->put('id'));
            $this->response($data;
        }
    
        function user_delete()
        {
            $data = array('returned: '. $this->delete('id'));
            $this->response($data);
        }
    }
    ?>

    以上代码中包含了如下几个片段,下面逐一讲解:

    $this->get() ——  其中,使用这个从形如index.php/example_api/user?id=1或者如index.php/example_api/user/id/1的连接中获得资源,比如这里就获得其id的值,然后在数组中返回该id对应的数值。

    $this->post() —— 其实是CodeIgniter中调用了其框架的$this->input->post()方法,进行提交操作,并且利用了XSS保护特性。

    $this->put() —— 取curl中提交的或者HTTP协议头的PUT参数的内容。
    $this->delete() —— 取curl中提交的或者HTTP协议头的delete参数的内容。
    $this->response() —— 个方法中,主要是将处理的数据返回给浏览器,你可以指定一个HTTP状态码去表示该次返回结果的状态,比如在数据库中找不到某个记录,可以使用如$this->response(array(‘error’ => ‘User not found.’)去返回结果。

    步骤4 与现有应用整合

    在下载的示例程序中,我们刚才讲解了重要的部分,接下来讲解如何将下载程序中的关键类与现有的应用整合。下载的应用中,结构如下图:

    restserver-important-files.png

    注意:较新版本需要将application\libraries\Format.php和application\libraries\REST_Controller.php文件到你自己的项目的application\libraries目录下,复制application\config\rest.php文件到自己项目目录下,复制application\language\english\rest_controller_lang.php到自己项目对应目录下。


    这里假设要从你的应用的后端实体模型中进行相关操作,并将操作发布成RESTful的webservice,因此修改代码如下:

    <?
    require(APPPATH.'/libraries/REST_Controller.php');
    
    class Api extends REST_Controller
    {
        function user_get()
        {
            if(!$this->get('id'))
            {
                $this->response(NULL, 400);
            }
    
            $user = $this->user_model->get( $this->get('id') );
    
            if($user)
            {
                $this->response($user, 200); // 200 being the HTTP response code
            }
    
            else
            {
                $this->response(NULL, 404);
            }
        }
    
        function user_post()
        {
            $result = $this->user_model->update( $this->post('id'), array(
                'name' => $this->post('name'),
                'email' => $this->post('email')
            ));
    
            if($result === FALSE)
            {
                $this->response(array('status' => 'failed'));
            }
    
            else
            {
                $this->response(array('status' => 'success'));
            }
    
        }
    
        function users_get()
        {
            $users = $this->user_model->get_all();
    
            if($users)
            {
                $this->response($users, 200);
            }
    
            else
            {
                $this->response(NULL, 404);
            }
        }
    }
    ?>

    以上的代码段其实之前都已经介绍过,只不过这次在每个方法中,读取的是后端数据库中的实体类而已。

    步骤5 保护RESTful API

    为了保护RESTful API,可以在application/config/rest.php中设置安全保护级别,如下所示:

    $config['rest_auth'] = 'basic';

    其中保护级别有如下设置:

    None:任何人都可以访问这个API
    BASIC:这个设置中,只提供基本的验证方式,适合在内部网络使用
    Digest:使用用户名和密码进行验证,比如:$config['rest_valid_logins'] = array('admin' => '1234');


    第二部分 调用RESTful服务


    接下来,我们讲解如何调用RESTful服务,因为RESTful服务是通过HTTP协议进行发布服务,因此有多种方法进行调用。

    1) 通过file_get_contents()调用

    可以通过PHP中最简单的file_get_contents()去调用RESTful,比如:

    $user = json_decode(file_get_contents('http://example.com/index.php/api/user/id/1/format/json'));
    echo $user;

    要注意的是,要是访问一个受密码保护的RESTful的话,需要用如下形式访问:

    $user = json_decode(
        file_get_contents('http://admin:1234@example.com/index.php/api/user/id/1/format/json')
    );
    echo $user->name;

    2)使用cUrl访问RESTful

    使用php中的cUrl去访问RESTful服务时最方便稳定的,下面的代码指导如何使用cUrl去设置HTTP协议头,去更新一个指定用户的信息,如下代码所示:

    function native_curl($new_name, $new_email) {
        $username = 'admin';
        $password = '1234';
    
        // Alternative JSON version
        // $url = 'http://twitter.com/statuses/update.json';
        // Set up and execute the curl process
        $curl_handle = curl_init();
        curl_setopt($curl_handle, CURLOPT_URL, 'http://localhost/restserver/index.php/example_api/user/id/1/format/json');
        curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($curl_handle, CURLOPT_POST, 1);
        curl_setopt($curl_handle, CURLOPT_POSTFIELDS, array(
            'name' => $new_name,
            'email' => $new_email
        ));
    
        //本行可选,如果你的RESTful API是开放的,则请删除该行
        curl_setopt($curl_handle, CURLOPT_USERPWD, $username . ':' . $password);
    
        $buffer = curl_exec($curl_handle);
        curl_close($curl_handle);
    
        $result = json_decode($buffer);
    
        if (isset($result->status) && $result->status == 'success') {
            echo 'User has been updated.';
        } else {
            echo 'Something has gone wrong';
        }
    }

    用过PHP的cUrl的朋友应该知道,这里其实是使用cUrl对我们已经发布的RESTful地址进行访问,并提交相关要更新的参数。但是,强大的CodeIgniter为我们封装了更强大的cUrl类库cUrl library(https://github.com/EllisLab/CodeIgniter/wiki/Curl-library)

    上面的代码可以简化如下:

    function ci_curl($new_name, $new_email) {
        $username = 'admin';
        $password = '1234';
        $this->load->library('curl');
        $this->curl->create('http://localhost/restserver/index.php/example_api/user/id/1/format/json');
        //本行可选,如果你的RESTful API是开放的,则请删除该行        $this->curl->http_login($username, $password);
        $this->curl->post(array(
            'name' => $new_name,
            'email' => $new_email
        ));
        $result = json_decode($this->curl->execute());
        if (isset($result->status) && $result->status == 'success') {
            echo 'User has been updated.';
        } else {
            echo 'Something has gone wrong';
        }
    }

    3)使用REST Client类库访问

    第三种方法是可以使用开源的REST Client类库(https://github.com/philsturgeon/codeigniter-restclient)去访问REST,比如同样上面的代码,可以写成:

    function rest_client_example($id) {
        $this->load->library('rest', array(
            'server' => 'http://localhost/restserver/index.php/example_api/',
            'http_user' => 'admin',
            'http_pass' => '1234',
            'http_auth' => 'basic' // 或者使用'digest'
        ));
        $user = $this->rest->get('user', array('id' => $id), 'json');
        echo $user->name;
    }

    看,是不是更简单了!这里是示例说明了调用GET方法,并且说明返回的形式是JSON的,当然你也可以指定其他形式的返回结果,比如xml,php,csv等,比如:

    $user = $this->rest->get('user', array('id' => $id), 'application/json');

    同理,可以使用$this->rest->post(),$this->rest->put(),$this->rest->delete()等。

    最后,我们学习下如何跟twitter的RESTful API打交道,使用RESTful Client library,只需要如下这样的编写简单代码即可:

    这个是调用twitter的RESTful API去获得某个用户ID的资料

    $this->load->library('rest', array('server' => 'http://twitter.com/'));
    $user = $this->rest->get('users/show', array('screen_name' => 'philsturgeon'));

    这个代码段则是更新某个用户的状态

    $this->load->library('rest', array(
        'server' => 'http://twitter.com/',
        'http_user' => 'username',
        'http_pass' => 'password',
        'http_auth' => 'basic'
    ));
    $user = $this->rest->post('statuses/update.json', array('status' => 'Using the REST client to do stuff'));


    简单例子演示:


    (1)、用数组代理数据库api调用演示:

    <?php
    
    defined('BASEPATH') OR exit('No direct script access allowed');
    require APPPATH . '/libraries/REST_Controller.php';
    class Mytest extends \Restserver\Libraries\REST_Controller {
        function __construct()
        {
            // Construct the parent class
            parent::__construct();
        }
    
        public function index_get()
        {
    
            // 用数组模仿数据库
            $users = [
                ['id' => 1, '姓名' => '胡新春', 'email' => 'im@huxinchun.com', '爱好' => '睡觉'],
                ['id' => 2, 'name' => 'Jim', 'email' => 'jim@example.com', 'fact' => 'Developed on CodeIgniter'],
                ['id' => 3, 'name' => 'Jane', 'email' => 'jane@example.com', 'fact' => 'Lives in the USA', ['hobbies' => ['guitar', 'cycling']]],
            ];
    
            $id = $this->get('id');
    
            // (如果ID参数不存在返回所有用户)If the id parameter doesn't exist return all the users
    
            // 找到并返回一个特定的用户的一个记录。 Find and return a single record for a particular user.
    
            $id = (int) $id;
    
            $user = NULL;
    
            //如果数组非空
            if (!empty($users))
            {
            //将数组的值循环赋予value
                foreach ($users as $key => $value)
                {
                    if (isset($value['id']) && $value['id'] === $id)
                    {
                        $user = $value;
                    }
                }
            }
    
            if (!empty($user))
            {
                $this->set_response($user, \Restserver\Libraries\REST_Controller::HTTP_OK); 
                // OK(200)是HTTP响应代码 OK (200) being the HTTP response code
            }
     
        }
    
    }
    ?>

    访问方式:

    根目录/控制器名/id?1

    返回id=1的josn数据:

    http://localhost/api(根目录名)/(控制器名)mytest?id=1&format=json

    http://localhost/api(根目录名)/(控制器名)mytest?id=1

    返回id=1的xml数据:

    http://localhost/api(根目录名)/(控制器名)mytest?id=1&format=xml


    (2)本地数据库api调用的小例子


    <?php
    defined('BASEPATH') OR exit('No direct script access allowed');
    require APPPATH . '/libraries/REST_Controller.php';
    class Api extends \Restserver\Libraries\REST_Controller {
    
        function __construct()
        {
            // Construct the parent class
            parent::__construct();
    
        }
    
        public function index_get()
        {
    
            if(empty($_GET['uid'])){
                $this->response(array('error'=>'条件不能为空!',400));
            }
    
            $table = "user";
            $query = $this->db->get_where($table,array('uid'=>1));
            $data = $query->row_array();
            
    
            if(empty($data)){
                $this->response(array('status'=>1));
            }else{
                $this->response($data);
            }
        
        }
    }
    ?>

    如上需要配置好ci框架的数据库

    20170913112742911.jpg

    数据表名:user

    访问方式:

    根目录/控制器名/uid?1

    返回uid=1的josn数据:

    http://localhost/api(根目录名)/(控制器名)mytest?uid=1&format=json

    http://localhost/api(根目录名)/(控制器名)mytest?uid=1

    返回uid=1的xml数据:

    http://localhost/api(根目录名)/(控制器名)mytest?uid=1&format=xml


    参考文献:

    https://code.tutsplus.com/tutorials/working-with-restful-services-in-codeigniter--net-8814

    https://github.com/chriskacerguis/codeigniter-restserver

    https://jingyan.baidu.com/article/154b46317556d428ca8f4115.html

    点评一下

    
    程序:HXC博客v1.0+ 主题:HXC博客前端Funs主题    环境:lamp  后台
    博客平稳运行2年+