软件开发工具包(Software Development Kit, SDK)通常是一些被软件工程师用于为特定的软件包、软件框架、硬件平台、操做系统等建立应用软件的开发工具的集合。php
在web开发领域,咱们接触的sdk一般是为了调用开放接口而封装好的公司外的第三方库。好比,各大互联网公司在几年前都作了开发者平台html
Github: GitHub API v3git
Weibo: API - 微博APIgithub
Twitter: dev.twitter.com/web
Instagram: www.instagram.com/developer/算法
能够理解为,为了调用开放接口,sdk就是为了方便调用才封装好了一些方法和工具。咱们能够尝试总结下咱们接触的开放接口的特色:编程
GET
/ POST
请求方式,传递数据,而且通常都有接入方的凭证,如 TOKEN
SIGN
等;array
类型,一会儿打包就 post
过去,虽然这样最简单省事,可是这样可读性并很差;提倡把接口数据抽象成一个对象,一个接口对应一个类,利用 传输对象模式;<?php
/** * Class AbstractRequestBody */
abstract class AbstractRequestBody {
/** * @var string $path * 由于每一个接口的路径不一样,因此须要每一个接口都显示的指定请求路径 */
protected $path;
/** * @var array $data * 咱们把每一个接口的业务参数最后统一收纳在data数组中 */
protected $data = [];
/** * AbstractRequestBody constructor. */
public function __construct() {
$this->setPath();
}
/** * @return mixed * 假若有必要,每一个接口均可以进行一些自定义的参数校验 */
abstract public function validate();
/** * @param $response * * @return mixed */
abstract public function transfer(&$response);
/** * @return string * 最后发起请求的时候获取接口路径 */
public function getPath() {
return $this->path;
}
/** * @return mixed * 抽象化对象,强制要求每一个接口类必须设定接口路径 */
abstract protected function setPath();
/** * @return array * 须要打包的一些公共参数 */
public function package(): array {
$data = $this->getData();
$params['data'] = json_encode($data, 320);
$params['version'] = Constants::VERSION;
$params['nonce_str'] = Utils::getNonceStr();
$params['sign'] = Utils::sign($params);
return $params;
}
protected function getData() {
return $this->data;
}
}
复制代码
<?php
/** * Class OneApi */
class OneApi extends AbstractRequestBody {
public function setOneParam($value) {
$this->data['one_param'] = $value;
// 为实现可链式调用
return $this;
}
public function setTwoParam($value) {
$this->data['two_param'] = $value;
// 为实现可链式调用
return $this;
}
/** * ...更多参数 */
/** * 自定义的参数验证 */
public function validate() {
// TODO: Implement validate() method.
}
/** * 字段转换 */
public function transfer(&$response) {
// TODO: Implement transfer() method.
}
protected function setPath() {
$this->path = '/path/api';
}
}
复制代码
<?php
/** * Class Utils */
class Utils {
/** * @param int $length * @return string */
public static function getNonceStr() {
}
/** * 签名算法 * 可能要须要用到key 或 私钥文件 * @param array $params * @return string */
public static function sign(array $params): string {
}
/** * 验证接口返回数据 * @param array $params * @return bool */
public static function verifySign(array $params): bool {
}
}
复制代码
若是常量比较多,建议根据功能分类作成多个文件。json
<?php
/** * Class Constants */
class Constants {
const DOMAIN_PROD = 'https://open.api.com';
const VERSION = '1.0.0';
const SIGN_TYPE = 'MD5';
/** * 接口其余相关常量 */
}
复制代码
这里只作简单示例,配置也能够作成 return array()
的形式,而后加载,或者相似 Laravel 利用 env
函数从环境变量取;api
有一个原则是:代码配置安全的检测标准之一是代码库是否可当即开源。数组
<?php
/** * Class Config */
class Config {
const SIGN_MD5_KEY = '1111111111111';
const SERVICE_ID = '1213444543545';
}
复制代码
<?php
/** * Class SdkClient */
class SdkClient {
/** * @param AbstractRequestBody $requestBody * @param int $timeout * @return string */
public function send($requestBody, int $timeout = 15) {
try {
// 校验参数
$requestBody->validate();
// 拼凑url
$url = Constants::DOMAIN_PROD . $requestBody->getPath();
// 获取请求参数
$data = $requestBody->package();
// 发送请求并通过一层统一转换
$response = $this->response(
$this->post(
$url,
$data,
$timeout
)
);
// 若比较特殊的格式转换,能够在各自请求类中进行响应过滤,响应数据是传引用的,直接处理便可
$requestBody->transfer($response);
} catch (\Exception $exception) {
// TODO: 异常处理 $response = ...
}
return $response;
}
/** * 对返回数据统一处理,数据过滤 * 好比转换成数组,仍是对象,若是是对象能够new Response,在构造函数处理 * @param string $content * @return string */
private function response(string $content) {
return $content;
}
/** * TODO: 这里亦可根据需求,替换成项目可用的http包 * @param string $url * @param array $fields * @param int $timeout * @return bool|string */
private function post(string $url, array $fields, int $timeout = 10) {
$headers = ['Content-Type: application/json;charset=UTF-8',];
$ch = curl_init();
array_push($headers, "Expect:");
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
// ...
return curl_exec($ch);
}
}
复制代码
<?php
class Demo {
private $sdk_client;
public function __construct() {
$this->sdk_client = new SdkClient();
}
public function testOneApi() {
$request = new OneApi();
$request->setOneParam('3333')
->setTwoParam('1111');
print_r($this->sdk_client->send($request));
}
}
复制代码
以前封装了调用新支付开放平台的sdk,工程目录做为参考
总结这个封装套路是在接了几个支付渠道后,不断尝试总结出来的;而且有借鉴Java中面向对象的设计思路;
特别适合业务参数比较多、接口比较多、逻辑复杂、签名严格的场景下封装抽象出这几个类。
假如参数比较少请求比较简单,好比 GET
请求一两个参数,尚未特别复杂的签名算法的状况下,这种显然是不适合的,这只会徒增工做量。
以上代码只是做为一个参考,尝试总结封装的套路,还有细节和不完善的地方。
前段时间按照这些思路封装了一个钉钉聊天机器人sdk,能够做为参考,欢迎 star 或 下载 composer require baiyutang/dingtalk-chatbot