模擬優(yōu)酷開放平臺(tái)接口項(xiàng)目開發(fā)

2018-11-21 21:33 更新

4.2.1 模擬的業(yè)務(wù)場(chǎng)景

在這個(gè)開發(fā)實(shí)戰(zhàn)中,我們將模擬實(shí)現(xiàn)優(yōu)酷的開放平臺(tái)接口,即:http://open.youku.com/docs

但這里不涉及具體的內(nèi)部開發(fā)(我們也確實(shí)不得而知),而是只從外部的角度,通過PhalApi框架搭建類似的平臺(tái)接口架構(gòu)。

4.2.2 優(yōu)酷URL分析與路由Rewrite

以下是優(yōu)酷平臺(tái)的部分接口URL:

#單條視頻基本信息(videos/show_basic)
https://openapi.youku.com/v2/videos/show_basic.json

#我的詳細(xì)信息(users/myinfo) 
https://openapi.youku.com/v2/users/myinfo.json

#評(píng)論創(chuàng)建(comments/create)
https://openapi.youku.com/v2/comments/create.json

#搜索節(jié)目通過關(guān)鍵詞(searches/show/by_keyword)
https://openapi.youku.com/v2/searches/show/by_keyword.json

從上面的接口URL,我們可以明顯發(fā)現(xiàn)一些規(guī)律。即:

URL =  接口域名 + 版本 + 相對(duì)路徑.json

與PhalApi接口規(guī)則的沖突

但在PhalApi框架中,我們是通過&service=XXX參數(shù)來(lái)指定需要的服務(wù)的。為此,我們需要在服務(wù)端配置一些Rewrite規(guī)則以支持這些URL。 簡(jiǎn)單地,我們可以這樣在nginx配置:

    if ( !-f $request_filename )
    {
        rewrite ^/v2/(.*)/(.*).json /v2/?service=$1.$2;
    }

并為了更兼容PhalApi的風(fēng)格,我們?cè)谌肟谖募⒔邮盏降膕ervice首字母強(qiáng)制為大寫,即:

//$ vim ./Public/v2/index.php

if (isset($_REQUEST['service'])) {
    $_REQUEST['service'] = ucwords($_REQUEST['service']);
}

重啟一下nginx后,我們可以有瀏覽器,試著訪問:

https://openapi.youku.com/v2/videos/show_basic.json

我們將會(huì)看到:

{
    "ret": 400,
    "data": [
    ],
    "msg": "非法請(qǐng)求:接口服務(wù)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;
    }

}

4.2.3 項(xiàng)目的主要目錄結(jié)構(gòu)

首先,我們建立了一個(gè)Youku的項(xiàng)目目錄,并按不同的版本劃分了不同的模塊,如:

$ 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

4.2.4 簡(jiǎn)單的模擬實(shí)現(xiàn)

現(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' => '應(yīng)用Key'),
                'videoId' => array('name' => 'video_id', 'desc' => '視頻ID'),
                'videoUrl' => array('name' => 'video_url', 'desc' => '視頻播放頁(yè)URL'),
            ),
        );
    }

    /**
     * 單條視頻基本信息(videos/show_basic)
     * 
     * @return string id 視頻唯一ID 
     * @return string title 視頻標(biāo)題
     * @return string link 視頻播放鏈接
     * @return string thumbnail 視頻截圖
     * @return int duration 視頻時(shí)長(zhǎng),單位:秒
     * @return ... ...
     */
    public function show_basic() {

    }
}

然后,使用瀏覽器在線訪問接口文檔,訪問:

http://openapi.youku.com/v2/checkApiParams.php?service=Videos.show_basic

可以看到:
a pic
可以看出,這與優(yōu)酷平臺(tái)上的接口文檔是非常相近的。

最后,我們可以簡(jiǎn)單模擬實(shí)現(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" : "當(dāng)一個(gè)人在一座城市搬11次家。就意味著準(zhǔn)備在這個(gè)城市買房了。",
                "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);
    }

4.2.5 接口調(diào)用效果

雖然是模擬返回(其實(shí)是直接強(qiáng)制返回優(yōu)酷開放平臺(tái)上的示例數(shù)據(jù)),但我們還是可以來(lái)看下在模擬實(shí)現(xiàn)后的接口調(diào)用效果。

首先,是缺少client_id時(shí)的非法請(qǐng)求:

#請(qǐng)求
http://openapi.youku.com/v2/videos/show_basic.json

#返回
{
    "ret": 400,
    "data": [
    ],
    "msg": "非法請(qǐng)求:缺少必要參數(shù)client_id"
}

然后,嘗試一個(gè)合法的請(qǐng)求:

#請(qǐng)求
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": "當(dāng)一個(gè)人在一座城市搬11次家。就意味著準(zhǔn)備在這個(gè)城市買房了。",
        "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": ""
}

很好,目前運(yùn)行效果相當(dāng)流暢。
雖然如此,但我們明顯看到了問題所在。

4.2.6 返回格式的自行調(diào)整

在上一節(jié)中,我們很明顯看到了返回格式與優(yōu)酷現(xiàn)有的不一樣,因?yàn)镻halApi框架多了一層。
其實(shí),這些調(diào)整對(duì)于不同的項(xiàng)目來(lái)說(shuō),都是非常簡(jiǎn)單。

當(dāng)項(xiàng)目需要返回的格式有定制化需求時(shí),可以先自實(shí)現(xiàn)response服務(wù),再注冊(cè)。
在此場(chǎng)景,即:

先自定義response服務(wù)

我們先創(chuàng)建一個(gè)公共的目錄./Youku/Common,再創(chuàng)建項(xiàng)目需要的特定響應(yīng)類:

//$ vim ./Youku/Common/Response.php

<?php

class Common_Response extends PhalApi_Response_Json {

    public function getResult() {
        return $this->data;
    }
}

注冊(cè)response服務(wù)

接著,我們對(duì)response進(jìn)行注冊(cè):

//$ vim ./Public/v2/index.php

//裝載你的接口
DI()->loader->addDirs(array('Youku', 'Youku/V2'));

DI()->response = 'Common_Response';

這里需要稍微注意一下,我們要在裝載Youku目錄后,才能注冊(cè)DI()->response。

再次返回

回到剛才那個(gè)請(qǐng)求鏈接,我們可以發(fā)現(xiàn),當(dāng)再次調(diào)用時(shí),會(huì)返回:

{
    "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": "當(dāng)一個(gè)人在一座城市搬11次家。就意味著準(zhǔn)備在這個(gè)城市買房了。",
    "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"
    ]
}

4.2.7 簽名驗(yàn)證

以上我們調(diào)整了返回格式,這使得我們的項(xiàng)目開發(fā),越來(lái)越達(dá)到優(yōu)酷開放平臺(tái)接口的標(biāo)準(zhǔn)了(當(dāng)然,是假設(shè))。

但有一點(diǎn),我們是不能忽視的,在很多項(xiàng)目中同樣是不能忽視的。那就是:接口的簽名驗(yàn)證。

我們可以先來(lái)看下優(yōu)酷開放平臺(tái)是怎么處理接口簽名的。

簡(jiǎn)單地,優(yōu)酷會(huì)為每一個(gè)接入方提供一個(gè)client_id,然后在每次接口請(qǐng)求時(shí),通過都需要傳遞此參數(shù)。

為此,我們針對(duì)這個(gè)client_id編寫一個(gè)簡(jiǎn)單的客戶端驗(yàn)證服務(wù)。如:

//$ 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');
        }
    }
}

然后,在入口處注冊(cè)一下:

//$ vim ./Public/v2/index.php 

DI()->filter = 'Common_ClientCheck';

當(dāng)我們,再次打開剛才那個(gè)鏈接:

http://openapi.youku.com/v2/videos/show_basic.json?client_id=test

我們會(huì)看到空的返回:

[]

這說(shuō)明,對(duì)客戶端的非法請(qǐng)求已攔截成功,但這樣用戶體驗(yàn)明顯不好,因?yàn)闆]有任何的錯(cuò)誤提示輸出。

為此,我們需要回到剛才自定義的響應(yīng)類,修改一下:

//$ 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)酷平臺(tái)接口近似的返回了!

{
    "error": {
        "code": ,
        "type": "SystemException",
        "description": "非法請(qǐng)求:illegal client id"
    }
}

如需要能返回?cái)?shù)據(jù),我們只需要傳遞正確的client_id(目前是固定的兩個(gè))即可:

http://openapi.youku.com/v2/videos/show_basic.json?client_id=phalapi

4.2.8 尾聲

當(dāng)然,此次的優(yōu)酷接口模擬開發(fā),我們都只是很簡(jiǎn)單地表面說(shuō)明。

這樣的目的,不是為了讓大家真的去了解優(yōu)酷接口的內(nèi)部實(shí)現(xiàn),而是向大家展示,通過PhalApi框架,我們可以更靈活地實(shí)現(xiàn)各種業(yè)務(wù)需求和非功能性的需求。

希望對(duì)大家有幫助,夜已深,安。

源代碼請(qǐng)?jiān)L問:

https://git.oschina.net/dogstar/PhalApi-Demo-Youku.git

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)