codecamp

统一的接口请求方式:?sevice=XXX.XXX

有句话说得好,最可怕的事情不是别人比你优秀,而是优秀的人竟然还比你更努力。 --《考拉小巫的留学成长日志》

此篇章主要是讲述接口统一请求的方式,以及提供一个PHP实现的简单客户端。

1.13.1 指定接口服务:?service=XXX.XXX

我们统一固定用service参数来表示需要请求获得的服务,并通过GET方式传递,即请求的URI格式为:

接口域名 + 入口路径 + ?service=XXX.XXX

如:
http://dev.phalapi.com   +   /demo/  +  ?service=User.GetBaseInfo

当我们在浏览器以GET方式请求时,可以在nignx看到这样的日志:

127.0.0.1 - - [07/Feb/2015:22:46:46 -0800] "GET /demo/?service=User.GetBaseInfo&sign=&user_id=1 HTTP/1.1" 200 107 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:11.0) Gecko/20100101 Firefox/11.0"

如果通过接口用POST方式请求,则会看到:

127.0.0.1 - - [07/Feb/2015:19:32:05 -0800] "POST /demo/?service=User.GetBaseInfo&sign= HTTP/1.1" 200 135 "-" "-"

这里service的名称,开头不区分大小写,建议统一以大写开头,以显得专业。对应的接口是:

class Api_User extends PhalApi_Api {

    public function getBaseInfo() {
    }
}

1.13.2 统一参数用GET

在一个项目中,会有很多公共的接口参数,如客户端、版本号、密钥等。这些同样可以纳入GET参数里面,或者也可以放到POST里面。

温馨提示:
这样要求是有目的的,因为这样的话可以在nginx的access日志里面查看来自客户端的快照信息,以便统计或者定位问题。

1.13.3 接口参数用POST

特别地,接口参数我们建议统一使用POST方式传递,理由很简单:

  • 1、相对保护上传的数据,一如密码;
  • 2、避免特殊字符或者过大数据包在GET下的限制;

1.13.4 获取Header头信息

每个请求都有自己的Header头,获取Header头信息可以判断请求来源或者是把一些敏感的内容存放到Header头信息中(如:加密后的参数),框架也提供了方便快捷获取Header的方法:

DI()->request->getHeader("Host");

1.13.5 测试下的模拟参数

默认地,PhalApi框架会将$_REQUEST作为接口参数的来源:

DI()->request = 'PhalApi_Request';

当我们需要统一强制用$_GET,可以在init.php文件中这样简单定制:

DI()->request = new PhalApi_Request($_GET);

同样,也可以在init.php文件中强制用$_POST:

DI()->request = new PhalApi_Request($_POST);

在测试环境下,为了模拟接口请求,我们需要人工提供接口参数,因此可以这样轻松模拟:

$str = 'service=User.GetBaseInfo&user_id=1';

parse_str($str, $params);
DI()->request = new PhalApi_Request($params);

1.13.6 PHP接口客户端示例

先看下调用和使用的代码示例:

<?php
require_once './PhalApiClient.php';

$config = array(
    'host' => 'http://dev.phalapi.com/demo',
    'secrect' => '******'
);

$client = new PhalApiClient($config);
$rs = $client->request('User.GetBaseInfo', array('userId' => 1));

if ($client->getRet() == PhalApiClient::RET_OK) {
    var_dump($rs);
} else {
    var_dump($client->getMsg());
    var_dump($client->getUrl());
}

附调用接口的客户端源代码:

//$ vim ./PhalApiClient.php
<?php

class PhalApiClient
{
    protected $host;
    protected $secrect = '';

    protected $params = array();

    protected $moreParams = array();

    protected $url;
    protected $ret;
    protected $msg;
    protected $data = array();

    const RET_OK = 'OK';
    const RET_WRONG = 'WRONG';
    const RET_ERROR = 'ERROR';

    public function __construct($config)
    {
        $this->host = rtrim($config['host'], '/') . '/';
        $this->secrect = $config['secrect'];
    }

    public function request($service, $params = array(), $timeoutMs = 3000)
    {
        if (!empty($service)) {
            $this->params['service'] = $service;
        }
        $this->params['sign'] = $this->encryptAppKey($params, $this->secrect);
        $this->url = $this->host . '?' . http_build_query($this->params);
        $this->moreParams = $params;

        $rs = $this->doRequest($this->url, $params, $timeoutMs);

        if ($rs === false) {
            $this->ret = self::RET_ERROR;
            $this->msg = '后台接口请求超时';
            return $this->getData();
        }

        $rs = json_decode($rs, true);

        if (isset($rs['data']['code']) && $rs['data']['code'] != 0) {
            $this->ret = self::RET_WRONG;
            $this->msg = '接口调用失败[code =' . $rs['data']['code'] . ']' . ', 错误>信息:' . isset($rs['data']['msg']) ? $rs['data']['msg'] : '无';
            return $this->getData();
        }

        $this->ret = intval($rs['ret']) == 200 ? self::RET_OK : self::RET_WRONG;
        $this->data = $rs['data'];
        $this->msg = $rs['msg'];

        return $this->getData();
    }

    public function getRet()
    {
        return $this->ret;
    }

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

    public function getMsg()
    {
        return $this->msg;
    }

    public function getUrl()
    {
        return $this->url . '&' . http_build_query($this->moreParams);
    }

    protected function encryptAppKey($params, $secrect)
    {
        return '';
    }

    protected function doRequest($url, $data, $timeoutMs = 3000)
    {
        $ch = curl_init();

        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, $timeoutMs);

        if (!empty($data)) {
            curl_setopt($ch, CURLOPT_POST, 1);
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
        }

        $rs = curl_exec($ch);

        curl_close($ch);

        return $rs;
    }
}

参数规则:接口参数规则配置
统一的返回格式和结构:ret data msg
温馨提示
下载编程狮App,免费阅读超1000+编程语言教程
取消
确定
目录

八、视频教程

关闭

MIP.setData({ 'pageTheme' : getCookie('pageTheme') || {'day':true, 'night':false}, 'pageFontSize' : getCookie('pageFontSize') || 20 }); MIP.watch('pageTheme', function(newValue){ setCookie('pageTheme', JSON.stringify(newValue)) }); MIP.watch('pageFontSize', function(newValue){ setCookie('pageFontSize', newValue) }); function setCookie(name, value){ var days = 1; var exp = new Date(); exp.setTime(exp.getTime() + days*24*60*60*1000); document.cookie = name + '=' + value + ';expires=' + exp.toUTCString(); } function getCookie(name){ var reg = new RegExp('(^| )' + name + '=([^;]*)(;|$)'); return document.cookie.match(reg) ? JSON.parse(document.cookie.match(reg)[2]) : null; }