restful架构:
是就是目前最流行的一种互联网软件架构。它结构清晰、符合标准、易于理解、扩展方便,所以正得到越来越多网站的采用。具体理论请看我上一篇写的restful理论。本篇主要记录下关于restful的实践。
restful实践:
工具:
这次在ci框架+restful
主要文件:
在控制器中添加控制器类:Restful.php。
在头部包含REST_Controller.php文件并继承
require APPPATH.'/libraries/REST_Controller.php'; class Widgets extends REST_Controller
在routes.php文件添加路由:
$route['Admin/([A-Za-z0-9]+)/(\d+)'] = "Admin/$1/index/$2";//路由可以根据个人的需求更改
在config/文件夹下添加rest.php文件。用于rest的配置(我这边都是返回地xml格式,如果需要返回其它格式,可以修改rest.php配置文件)
/* |-------------------------------------------------------------------------- | REST Format |-------------------------------------------------------------------------- | | What format should the data be returned in by default? | | Default: xml | */ $config['rest_default_format'] = 'xml';
具体代码解释:在application/libraries/文件下添加REST_Controller.php文件
restful get的请求:
用Chrome浏览器的postman插件模拟http请求:function index_get($id = '') { // Example data for testing. $widgets = array( 1 => array('id' => 1, 'name' => 'sprocket'), 2 => array('id' => 2, 'name' => 'gear') ); if (!$id) { $id = $this->get('id'); }//get方法调用的是REST_Controller类 中的http get方式带的参数 if (!$id) { if($widgets) $this->response($widgets, 200); // 200 being the HTTP response code//REST_Controller类中的指定格式的输出。默认xml else $this->response(array('error' => 'Couldn\'t find any widgets!'), 404); } //$widget = $this->widgets_model->getWidget($id); $widget = @$widgets[$id]; // test code if($widget) $this->response($widget, 200); // 200 being the HTTP response code else $this->response(array('error' => 'Widget could not be found'), 404);//responce方式是调用的ci框架的output类输出的 }
解释:
(1)Admin是ci控制器下的新建目录。 rest.com/Admin/restful/2 根据自己上面定义的路由规则。路由到/Admin/restful/index/2
(2)在继承REST_Controller类中走的_remap()方法。会走到/Admin/restful/index_get 因为是get方式请求。所以是index_get
(3)2作为参数放在REST_Controller类的成员属性中function _remap($object_called) { $controller_method = $object_called.'_'.$this->method; if(method_exists($this, $controller_method)) { $this->$controller_method(); } else { show_404(); } }
function __construct() { parent::__construct(); // How is this request being made? POST, DELETE, GET, PUT? $this->method = $this->_detect_method();//get // Lets grab the config and get ready to party $this->load->config('rest'); if($this->config->item('rest_auth') == 'basic') { $this->_prepareBasicAuth(); } elseif($this->config->item('rest_auth') == 'digest') { $this->_prepareDigestAuth(); } // Set up our GET variables $this->get_args = $this->uri->uri_to_assoc();//获取参数 $this->get_args = array_keys($this->get_args); $this->get_args = array('id'=>$this->get_args[0]); //var_dump($this->put_args); // Set up out PUT variables parse_str(file_get_contents('php://input'), $this->put_args);// put 是以表单的形式发送 // Merge both for one mega-args variable $this->args = array_merge($this->get_args, $this->put_args); // Which format should the data be returned in? $this->format = $this->_detect_format();//设置参数方式 json 、 xml }
restful post请求:
function index_post() { //var_dump($this->post('name')); $data = $this->post('name'); //$data = $this->_post_args; try { //$id = $this->widgets_model->createWidget($data); $id = 3; // test code //throw new Exception('Invalid request data', 400); // test code //throw new Exception('Widget already exists', 409); // test code } catch (Exception $e) { // Here the model can throw exceptions like the following: // * For invalid input data: new Exception('Invalid request data', 400) // * For a conflict when attempting to create, like a resubmit: new Exception('Widget already exists', 409) $this->responce(array('error' => $e->getMessage()), $e->getCode()); } if ($id) { $widget = array('id' => $id, 'name' => $data); // test code //$widget = $this->widgets_model->getWidget($id); $this->responce($widget, 201); // 201 being the HTTP responce code } else $this->responce(array('error' => 'Widget could not be created'), 404); }
postman模拟请求:
restful put请求:
源代码获取put参数:
restful.php控制器文件 put代码:parse_str(file_get_contents('php://input'), $this->put_args);// put 是以表单的形式发送
public function index_put() { $data = $this->put(''); //$data = $this->_put_args; try { //$id = $this->widgets_model->updateWidget($data); $id = $data['id']; // test code //throw new Exception('Invalid request data', 400); // test code } catch (Exception $e) { // Here the model can throw exceptions like the following: // * For invalid input data: new Exception('Invalid request data', 400) // * For a conflict when attempting to create, like a resubmit: new Exception('Widget already exists', 409) $this->responce(array('error' => $e->getMessage()), $e->getCode()); } if ($id) { $widget = array('id' => $data['id'], 'name' => $data['name']); // test code //$widget = $this->widgets_model->getWidget($id); $this->responce($widget, 200); // 200 being the HTTP responce code } else $this->responce(array('error' => 'Widget could not be found'), 404); }
postman模拟http put请求:(注意put是x-www-form-urlencoded方式,也就是表单)
restful delete请求:
function index_delete($id = '') { // Example data for testing. $widgets = array( 1 => array('id' => 1, 'name' => 'sprocket'), 2 => array('id' => 2, 'name' => 'gear'), 3 => array('id' => 3, 'name' => 'nut') ); if (!$id) { $id = $this->get('id'); } if (!$id) { $this->responce(array('error' => 'An ID must be supplied to delete a widget'), 400); } //$widget = $this->widgets_model->getWidget($id); $widget = @$widgets[$id]; // test code if ($widget) { try { //$this->widgets_model->deleteWidget($id); //throw new Exception('Forbidden', 403); // test code } catch (Exception $e) { // Here the model can throw exceptions like the following: // * Client is not authorized: new Exception('Forbidden', 403) $this->responce(array('error' => $e->getMessage()), $e->getCode()); } $this->responce($widget, 200); // 200 being the HTTP responce code } else $this->responce(array('error' => 'Widget could not be found'), 404); }
postman模拟http delete请求:
关于restful实践一些思考&结论:
1.以上restful.php控制器类的 get、post、put、delete是业务逻辑处理,得根据业务场景修改。
2.get是资源的查询,post是资源的新建或者修改,put是资源的修改,delete是资源的删除,由于put和delete可以由get&post代替,所以一般put和delete比较少见,post是资源新建,点击多次请求时,返回的数据不一样,但是get、delete、put请求时不停的请求相同的URI返回的数据是一样的。
3.restful中URI资源定位符一般是:/resource_name/param。param是方法名称还是参数值?
我的思考是:
p1.方法名称是可变的。不指定方法名称的话不知道走哪个方法的逻辑
a1:方法名称可以是resource_get、resource_post、resource_put、resource_delete。也就是后面添加请求方式
p1:但是这样控制器只有这几个方法了。类似于数据库的CURD操作。不仅有select一个还有select所有等。
a1:restful规范是:param就是id值,因为一个id值一定可以找到一条资源
p1:首先资源不一定知道id而是知道这资源的其它特性,还有id可以和上文put请求一样放在header的请求头中。
我公司用到的restful架构中 param就是指定方法的。但是在网上看都是id值。有没有知道param到底是id值还是方法名,还是说根据业务场景而定?