在這個開發(fā)實戰(zhàn)中,我們將模擬實現(xiàn)優(yōu)酷的開放平臺接口,即:http://open.youku.com/docs
但這里不涉及具體的內部開發(fā)(我們也確實不得而知),而是只從外部的角度,通過PhalApi框架搭建類似的平臺接口架構。
以下是優(yōu)酷平臺的部分接口URL:
#單條視頻基本信息(videos/show_basic)
https://openapi.youku.com/v2/videos/show_basic.json
#我的詳細信息(users/myinfo)
https://openapi.youku.com/v2/users/myinfo.json
#評論創(chuàng)建(comments/create)
https://openapi.youku.com/v2/comments/create.json
#搜索節(jié)目通過關鍵詞(searches/show/by_keyword)
https://openapi.youku.com/v2/searches/show/by_keyword.json
從上面的接口URL,我們可以明顯發(fā)現(xiàn)一些規(guī)律。即:
URL = 接口域名 + 版本 + 相對路徑.json
但在PhalApi框架中,我們是通過&service=XXX參數(shù)來指定需要的服務的。為此,我們需要在服務端配置一些Rewrite規(guī)則以支持這些URL。 簡單地,我們可以這樣在nginx配置:
if ( !-f $request_filename )
{
rewrite ^/v2/(.*)/(.*).json /v2/?service=$1.$2;
}
并為了更兼容PhalApi的風格,我們在入口文件將接收到的service首字母強制為大寫,即:
//$ vim ./Public/v2/index.php
if (isset($_REQUEST['service'])) {
$_REQUEST['service'] = ucwords($_REQUEST['service']);
}
重啟一下nginx后,我們可以有瀏覽器,試著訪問:
https://openapi.youku.com/v2/videos/show_basic.json
我們將會看到:
{
"ret": 400,
"data": [
],
"msg": "非法請求:接口服務Videos.show_basic不存在"
}
即表明Rewrite規(guī)則已生效,并能正常工作了,哈哈!
以下是更完整的nginx配置:
server {
root /path/to/openapi.youku.com/Public;
index index.html index.htm index.php;
error_log /var/log/nginx/.error_log;
access_log /var/log/nginx/openapi.youku.com.access_log;
server_name openapi.youku.com;
location / {
try_files $uri $uri/ /index.html;
}
if ( !-f $request_filename )
{
rewrite ^/v2/(.*)/(.*).json /v2/?service=$1.$2;
}
location ~ \.php$ {
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass 127.0.0.1:9000;
include fastcgi_params;
}
}
首先,我們建立了一個Youku的項目目錄,并按不同的版本劃分了不同的模塊,如:
$ tree ./Youku/
./Youku/
└── V2
├── Api
│ └── Default.php
├── Domain
├── Model
└── Tests
├── Api
├── Domain
├── Model
├── phpunit_user_getbaseinfo.xml
├── phpunit.xml
└── test_env.php
8 directories, 4 files
然后,為不同的版本,提供不同的入口,如:
$ tree ./Public/
./Public/
├── checkApiParams.php
├── index.php
├── init.php
└── v2
├── checkApiParams.php
├── index.php
└── listAllApis.php
1 directory, 6 files
現(xiàn)在,到了接口具體開發(fā)的環(huán)節(jié),我們將模擬開發(fā) 單條視頻基本信息(videos/show_basic)
首先,我們可以定義接口:
//$ vim ./Youku/V2/Api/Videos.php
<?php
class Api_Videos extends PhalApi_Api {
public function getRules() {
return array(
'show_basic' => array(
'clientId' => array('name' => 'client_id', 'require' => true, 'desc' => '應用Key'),
'videoId' => array('name' => 'video_id', 'desc' => '視頻ID'),
'videoUrl' => array('name' => 'video_url', 'desc' => '視頻播放頁URL'),
),
);
}
/**
* 單條視頻基本信息(videos/show_basic)
*
* @return string id 視頻唯一ID
* @return string title 視頻標題
* @return string link 視頻播放鏈接
* @return string thumbnail 視頻截圖
* @return int duration 視頻時長,單位:秒
* @return ... ...
*/
public function show_basic() {
}
}
然后,使用瀏覽器在線訪問接口文檔,訪問:
http://openapi.youku.com/v2/checkApiParams.php?service=Videos.show_basic
可以看到:
可以看出,這與優(yōu)酷平臺上的接口文檔是非常相近的。
最后,我們可以簡單模擬實現(xiàn):
public function show_basic() {
$rs = '{
"id" : "XMjg1MTcyNDQ0",
"title" : "泡芙小姐的燈泡 11",
"link" : "http://v.youku.com/v_show/id_XMjg1MTcyNDQ0.html",
"thumbnail" : "http://g4.ykimg.com/0100641F464E1FC...",
"duration" : "910",
"category" : "原創(chuàng)",
"state" : "normal",
"published" : "2011-07-15 09:00:42",
"description" : "當一個人在一座城市搬11次家。就意味著準備在這個城市買房了。",
"player" : "http://player.youku.com/player.php/sid/XMjg1MTcyNDQ0/v.swf",
"public_type" : "all",
"copyright_type" : "original",
"user" :
{
"id" : 58921428,
"name" : "泡芙小姐",
"link" : "http://u.youku.com/user_show/id_UMjM1Njg1NzEy.html"
},
"operation_limit": ["COMMENT_DISABLED"],
"streamtypes" : ["flv","flvhd","hd"]
}';
return json_decode($rs, true);
}
雖然是模擬返回(其實是直接強制返回優(yōu)酷開放平臺上的示例數(shù)據(jù)),但我們還是可以來看下在模擬實現(xiàn)后的接口調用效果。
首先,是缺少client_id時的非法請求:
#請求
http://openapi.youku.com/v2/videos/show_basic.json
#返回
{
"ret": 400,
"data": [
],
"msg": "非法請求:缺少必要參數(shù)client_id"
}
然后,嘗試一個合法的請求:
#請求
http://openapi.youku.com/v2/videos/show_basic.json?client_id=test
#返回
{
"ret": 200,
"data": {
"id": "XMjg1MTcyNDQ0",
"title": "泡芙小姐的燈泡 11",
"link": "http://v.youku.com/v_show/id_XMjg1MTcyNDQ0.html",
"thumbnail": "http://g4.ykimg.com/0100641F464E1FC...",
"duration": "910",
"category": "原創(chuàng)",
"state": "normal",
"published": "2011-07-15 09:00:42",
"description": "當一個人在一座城市搬11次家。就意味著準備在這個城市買房了。",
"player": "http://player.youku.com/player.php/sid/XMjg1MTcyNDQ0/v.swf",
"public_type": "all",
"copyright_type": "original",
"user": {
"id": 58921428,
"name": "泡芙小姐",
"link": "http://u.youku.com/user_show/id_UMjM1Njg1NzEy.html"
},
"operation_limit": [
"COMMENT_DISABLED"
],
"streamtypes": [
"flv",
"flvhd",
"hd"
]
},
"msg": ""
}
很好,目前運行效果相當流暢。
雖然如此,但我們明顯看到了問題所在。
在上一節(jié)中,我們很明顯看到了返回格式與優(yōu)酷現(xiàn)有的不一樣,因為PhalApi框架多了一層。
其實,這些調整對于不同的項目來說,都是非常簡單。
當項目需要返回的格式有定制化需求時,可以先自實現(xiàn)response服務,再注冊。
在此場景,即:
我們先創(chuàng)建一個公共的目錄./Youku/Common,再創(chuàng)建項目需要的特定響應類:
//$ vim ./Youku/Common/Response.php
<?php
class Common_Response extends PhalApi_Response_Json {
public function getResult() {
return $this->data;
}
}
接著,我們對response進行注冊:
//$ vim ./Public/v2/index.php
//裝載你的接口
DI()->loader->addDirs(array('Youku', 'Youku/V2'));
DI()->response = 'Common_Response';
這里需要稍微注意一下,我們要在裝載Youku目錄后,才能注冊DI()->response。
回到剛才那個請求鏈接,我們可以發(fā)現(xiàn),當再次調用時,會返回:
{
"id": "XMjg1MTcyNDQ0",
"title": "泡芙小姐的燈泡 11",
"link": "http://v.youku.com/v_show/id_XMjg1MTcyNDQ0.html",
"thumbnail": "http://g4.ykimg.com/0100641F464E1FC...",
"duration": "910",
"category": "原創(chuàng)",
"state": "normal",
"published": "2011-07-15 09:00:42",
"description": "當一個人在一座城市搬11次家。就意味著準備在這個城市買房了。",
"player": "http://player.youku.com/player.php/sid/XMjg1MTcyNDQ0/v.swf",
"public_type": "all",
"copyright_type": "original",
"user": {
"id": 58921428,
"name": "泡芙小姐",
"link": "http://u.youku.com/user_show/id_UMjM1Njg1NzEy.html"
},
"operation_limit": [
"COMMENT_DISABLED"
],
"streamtypes": [
"flv",
"flvhd",
"hd"
]
}
以上我們調整了返回格式,這使得我們的項目開發(fā),越來越達到優(yōu)酷開放平臺接口的標準了(當然,是假設)。
但有一點,我們是不能忽視的,在很多項目中同樣是不能忽視的。那就是:接口的簽名驗證。
我們可以先來看下優(yōu)酷開放平臺是怎么處理接口簽名的。
簡單地,優(yōu)酷會為每一個接入方提供一個client_id,然后在每次接口請求時,通過都需要傳遞此參數(shù)。
為此,我們針對這個client_id編寫一個簡單的客戶端驗證服務。如:
//$ vim ./Youku/Common/ClientCheck.php
<?php
class Common_ClientCheck implements PhalApi_Filter {
public function check() {
$clientId = DI()->request->get('client_id');
$allCliendIds = array(
'phalapi',
'oschina'
);
if (!in_array($clientId, $allCliendIds)) {
throw new PhalApi_Exception_BadRequest('illegal client id');
}
}
}
然后,在入口處注冊一下:
//$ vim ./Public/v2/index.php
DI()->filter = 'Common_ClientCheck';
當我們,再次打開剛才那個鏈接:
http://openapi.youku.com/v2/videos/show_basic.json?client_id=test
我們會看到空的返回:
[]
這說明,對客戶端的非法請求已攔截成功,但這樣用戶體驗明顯不好,因為沒有任何的錯誤提示輸出。
為此,我們需要回到剛才自定義的響應類,修改一下:
//$ vim ./Youku/Common/Response.php
<?php
class Common_Response extends PhalApi_Response_Json {
public function getResult() {
if ($this->ret != 200) {
return array(
'error' => array(
'code' => $this->ret,
'type' => 'SystemException',
'description' => $this->msg,
),
);
}
return $this->data;
}
}
再刷新一下,可以看到和優(yōu)酷平臺接口近似的返回了!
{
"error": {
"code": ,
"type": "SystemException",
"description": "非法請求:illegal client id"
}
}
如需要能返回數(shù)據(jù),我們只需要傳遞正確的client_id(目前是固定的兩個)即可:
http://openapi.youku.com/v2/videos/show_basic.json?client_id=phalapi
當然,此次的優(yōu)酷接口模擬開發(fā),我們都只是很簡單地表面說明。
這樣的目的,不是為了讓大家真的去了解優(yōu)酷接口的內部實現(xiàn),而是向大家展示,通過PhalApi框架,我們可以更靈活地實現(xiàn)各種業(yè)務需求和非功能性的需求。
希望對大家有幫助,夜已深,安。
https://git.oschina.net/dogstar/PhalApi-Demo-Youku.git
更多建議: