composer require gupo/http-client ^3.0本包的Http请求客户端继承关系:Gupo\HttpClient\HttpClient -> Cloudladder\Http\Client -> GuzzleHttp\Client
每个请求,在代码中直接调用 (new Client())->get("uri")
命令:php artisan gupo:http-client:install
\App\Services\Api\ApiService\App\Services\Api\Modules\\App\Services\Api\Support\BaseHttpClientconfig/apis.php\App\Services\Api\ApiService注册"类的别名"到"config/app.php"的"aliases"下,别名为Api/ ├── /app │ └── /Services # 服务层 │ └── /Api # Api服务 │ ├── /Modules # 模块层,里面的所有Api类,都继承BaseHttpClient │ │ ├──XxxApi.php # 子类-厂商A的Api │ │ ├──XxxApi.php # 子类-厂商B的Api │ │ ├──XxxApi.php # 子类-厂商C的Api │ │ └──XxxApi.php # 子类-厂商D的Api │ │ ... │ ├── /Support # 支持层 │ │ └──BaseHttpClient.php # Api抽象类 │ └── ApiService.php # Api访问出口 └── /config └── apis.php # api配置
每个厂商的的api的"站点地址"与其他相关配置,请配置到config/apis.php。获取配置时,用config('apis.xxx'),例config('apis.wdPay.url')。
注:配置文件中的内容,请从.env中获取,例:env('WD_PAY_URL')。
为单个厂商访问的所有Api在app\Services\Api\Modules\目录下单独建一个Api类,继承抽象类\App\Services\Api\Support\BaseHttpClient,类名建议为厂商名(如果厂商业务模块区分较为明确,也可以以厂商下的业务模块为单独建类的单位)。
例:
WdApi;WdPayApi;在\App\Services\Api\ApiService类中注册Api单例的唯一访问出口,当我们需要访问Api类时,只从此处进行访问。例:
<?php
declare(strict_types=1);
namespace App\Services\Api;
use App\Services\Api\Modules\EmrApi;
use App\Services\Api\Modules\WdPayApi;
use App\Services\Api\Modules\ZlbApi;
class ApiService
{
/**
* 万达-统一支付
*
* @return WdPayApi
*/
public static function wdPay(): WdPayApi
{
return WdPayApi::instance();
}
/**
* 浙里办
*
* @return ZlbApi
*/
public static function zlb(): ZlbApi
{
return ZlbApi::make();
}
/**
* 移动医生
*
* @return EmrApi
*/
public static function emr(): EmrApi
{
return EmrApi::make();
}
}
\Api::wdPay()
详见
\Gupo\HttpClient\HttpClient类对哪些方法进行了抽象
<?php
/**
* 获取-基础Uri
*/
abstract public function getBaseUri(): string;
/**
* 获取-日志实例
*/
abstract public function getLogger(): LoggerInterface;
/**
* 获取-Api名称
*/
abstract public function getApiName(): string;
如果针对单个厂商,需要进行初始化。例如需要配置appid、密钥等信息。请在public function init(){}中实现。init方法,会在实例化类时被自动调用。
通过该扩展包与该设计结构的结合,可以对\Gupo\HttpClient\HttpClient类,及该类引用的特性HandlerStackTrait、MiddlewareTrait、ResponseTrait、LogTrait中的属性与方法进行重新设置或重写。
\App\Services\Api\Support\BaseHttpClient类中。\App\Services\Api\Modules\厂商Api类类中。\Gupo\HttpClient\HttpClient,如下 <?php
/**
* @var string|null 基础uri,通过'getBaseUri'方法的返回值初始化
* 如果同一厂商的站点地址变更,请在"发起请求前"重写该属性
*/
protected ?string $base_uri;
/**
* @var LoggerInterface|null 日志实例,通过'getLogger'方法的返回值初始化
*/
public ?LoggerInterface $logger = null;
/**
* @var string|null 异常前缀
* 如果要个性化定义某个类的"异常前缀",请重写该属性
*/
protected ?string $default_exception_prefix = null;
/**
* @var int|null 超时时间(单位:秒)
*/
protected ?int $default_timeout = 10;
/**
* @var bool 是否执行"为4xx或5xx响应抛出异常"的中间件:true-执行;false-不执行;
*/
protected bool $default_http_errors = true;
/**
* 异常前缀
*
* @param string|null $exceptionPrefix
* @return string
* @author lyl
*/
public function exceptionPrefix(?string $exceptionPrefix = null): string;
/**
* 处理异常
* 请求过程中出现异常时,默认调用当前类。如果"全局-个性化处理异常",请在子类中"重写"该方法;如果"单请求-个性化处理异常",请在调用请求方法时传入"回调方法"
*
* @param Throwable $exception
* @param ResponseInterface|null $response
* @throws HttpClientException
* @throws Throwable
* @author lyl
*/
protected function handleException(\Throwable $exception, ?ResponseInterface $response): void;
\Gupo\HttpClient\Traits\HandlerStackTrait,如下 <?php
/**
* 头部的中间件(可重写)
*
* @return array<string|int, callable>
* @author lyl
*/
protected function headMiddlewareList(): array;
/**
* 尾部的中间件(建议根据系统实际情况重写)
*
* @return array<string|int, callable>
* @author lyl
*/
protected function tailMiddlewareList(): array;
<?php
/**
* 发起GET请求
*
* @param string $uri 请求地址
* @param array $query 请求数据-query
* @param array $middlewareList 中间件列表
* @param callable|null $handleException 自定义异常处理
* @param array $options 请求配置
* @return ResponseInterface|null
* @throws HttpClientException
* @throws Throwable
* @author lyl
*/
protected function get(
string $uri,
array $query = [],
array $middlewareList = [],
?callable $handleException = null,
array $options = []
);
/**
* 发起POST请求
*
* @param string $uri 请求地址
* @param array $query 请求数据-query
* @param array $json 请求数据-json
* @param array $formParams 请求数据-form_params
* @param array $middlewareList 中间件列表
* @param callable|null $handleException 自定义异常处理
* @param array $options 请求配置
* @return ResponseInterface|null
* @throws HttpClientException
* @throws Throwable
* @author lyl
*/
protected function post(
string $uri,
array $query = [],
array $json = [],
array $formParams = [],
array $middlewareList = [],
?callable $handleException = null,
array $options = []
)
options中的内容,详见 中文文档-请求选项 或 English Document-Request Options在Api类中,为某接口写一个请求方法。例:
<?php
public function getApplyDetail(string $card_no, int $id): array
{
$uri = '/open_api/application_patient/record/detail';
$response = $this->get(
uri: $uri,
query: [
'card_no' => $card_no,
'id' => $id,
],
);
return $this->getResponseValue($response);
}
有的厂商的BaseUri不是固定的,会根据不同接口或不同逻辑变更。像这种情况,可以在发起请求前,重写属性base_uri。例:
<?php
/**
* 获取-基础Uri
*/
public function getBaseUri(): string
{
return config('apis.emr.url');
}
/**
* 重写-基础Uri
*
* @param string $hid
*/
private function setBaseUri(string $main_hid)
{
$base_uri = $this->getBaseUri();
$this->base_uri = str_replace('{hid}', $main_hid, $base_uri);
}
/**
* 移动医生-接口转发
*/
public function relay(string $hid, string $url, array $query)
{
$main_hid = explode('_', $hid)[0];
// 重写-基础Uri
$this->setBaseUri((string) $main_hid);
$response = $this->get(
uri: $url,
query: $query,
handleResponse: $this->customHandleResponse(),
options: [
RequestOptions::HEADERS => [
'ase' => 'false',
],
],
);
return $this->getResponseValue($response);
}
例:
$data = \Api->emr()->relay($hid, $url, $query)