分类存档: HTTP

[转]用CodeIgniter搭建RESTful API

REST (REpresentation State Transfer) 指的是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是 RESTful。

用CodeIgniter整合好的RESTful框架:http://github.com/philsturgeon/codeigniter-restserver

请求URL格式:index.php/example_api/user/id/1/format/json。
其中,可以看到这种形式很象CodeIgniter中的MVC架构的链接,但要注意到,传统的CodeIgniter中的有点不同,在链接的最后一部分,我们称为Resource资源。

RESTful架构中的四类关于资源的操作:
GET:使用GET去获得一个已经存在的资源的信息。通常我们在浏览器中输入url其实即发出了一个GET的请求。
POST:使用POST去更新一个已经存在的资源。比如表单中的提交数据行为,都属于POST类型。
PUT:使用HTTP的报文头的PUT,可以去新建一种资源,目前不是所有浏览器支持,所以本文不作讨论。
DELETE:使用DELETE去删除一种资源,同样目前不是所有浏览器都支持。

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

<?php
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.’)去返回结果。

保护RESTful API

为了保护RESTful API,可以在application/config/rest.php中设置安全保护级别,如下所示:
$config['rest_auth'] = ‘basic’; //默认值为false
1)最简单的调用RESTful:

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

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

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

3)使用cUrl访问RESTful

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';
}
}

另外,强大的CodeIgniter为我们封装了更强大的cUrl类库cUrl library(http://codeigniter.com/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');
$this->curl->http_login($username, $password); //本行可选,如果你的RESTful API是开放的,则请删除该行
$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';
}
}

HTTP 协议

HTTP 304

304 的标准解释是:Not Modified 客户端有缓冲的文档并发出了一个条件性的请求(一般是提供If-Modified-Since头表示客户只想比指定日期更新的文档)。服务器告诉客户,原来缓冲的文档还可以继续使用。

如果客户端在请求一个文件的时候,发现自己缓存的文件有 Last Modified ,那么在请求中会包含 If Modified Since ,这个时间就是缓存文件的 Last Modified 。因此,如果请求中包含 If Modified Since,就说明已经有缓存在客户端。只要判断这个时间和当前请求的文件的修改时间就可以确定是返回 304 还是 200 。对于静态文件,例如:CSS、图片,服务器会自动完成 Last Modified 和 If Modified Since 的比较,完成缓存或者更新。但是对于动态页面,就是动态产生的页面,往往没有包含 Last Modified 信息,这样浏览器、网关等都不会做缓存,也就是在每次请求的时候都完成一个 200 的请求。

因此,对于动态页面做缓存加速,首先要在 Response 的 HTTP Header 中增加 Last Modified 定义,其次根据 Request 中的 If Modified Since 和被请求内容的更新时间来返回 200 或者 304 。虽然在返回 304 的时候已经做了一次数据库查询,但是可以避免接下来更多的数据库查询,并且没有返回页面内容而只是一个 HTTP Header,从而大大的降低带宽的消耗,对于用户的感觉也是提高。

当这些缓存有效的时候,查看一个请求会得到这样的结果:

第一次访问 200

鼠标点击二次访问 (Cache)

按F5刷新 304

按Ctrl+F5强制刷新 200

HTTP 3xx

301 Moved Permanently:请求的资源已经被赋予一个新的URL

header( "HTTP/1.1 301 Moved Permanently" ) ;
header( "Location:http://www.superzc.com" );

304 Not Modified:如果客户端已经完成一个有条件的请求并且是允许的,但是这个文档并没有改变,服务器应该返回304状态码。304状态码一定不能包含信息主体,从而通常通过一个头字段后的第一个空行结束

HTTP 4xx:客户端错误

400 Bad Request:因为错误的语法导致服务器无法理解请求信息
403 Forbidden:服务器接收请求,但是被拒绝处理
404 Not Found

HTTP 5xx:服务器错误

500 Internal Server Error:服务器遭遇异常阻止了当前请求的执行
502 Bad Gateway

第 1 页,共 1 页1