軟件開發工具包(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