gupo / http-client
辅助第三方请求的Http请求客户端
Requires
- php: ^7.4|^8.0
- ext-json: *
- cloudladder/http: ^1.2
- gupo/tool-install: ^3.0
- laravel/framework: ^6.20.26|^9.0
- dev-master
- v3.0.x-dev
- v3.0.4
- v3.0.3
- v3.0.2
- v3.0.1
- v2.1.2
- v2.1.1
- v2.0.x-dev
- v2.0.19
- v2.0.18
- v2.0.17
- v2.0.16
- v2.0.15
- v2.0.14
- v2.0.13
- v2.0.12
- v2.0.11
- v2.0.10
- v2.0.9
- v2.0.8
- v2.0.7
- v2.0.6
- v2.0.5
- v2.0.4
- v2.0.3
- v2.0.2
- v2.0.1
- v1.1.1
- v1.0.x-dev
- v1.0.19
- v1.0.18
- v1.0.17
- v1.0.16
- v1.0.15
- v1.0.14
- v1.0.13
- v1.0.12
- v1.0.11
- v1.0.10
- v1.0.9
- v1.0.8
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
This package is auto-updated.
Last update: 2025-01-10 08:15:02 UTC
README
- 发布人:鲁银莲
获取
- Coding:https://cloudladder.coding.net/p/business-common/d/business-httpclient/git
- Packagist:https://packagist.org/packages/gupo/http-client
- Composer:
composer require gupo/http-client ^3.0
环境
- PHP8.1+
- Laravel9.33.0+
包继承关系
本包的Http请求客户端继承关系:Gupo\HttpClient\HttpClient
-> Cloudladder\Http\Client
-> GuzzleHttp\Client
我们的包解决了什么问题?
我们普遍如何使用 Client 类?
每个请求,在代码中直接调用 (new Client())->get("uri")
当前有什么痛点?
- 请求的第三方接口,散在项目各处,无法实现统一管理
- 同厂商的“站点地址”需要在每次调用时都设置一次
- 其他配置无法实现“系统统一配置”、“单厂商统一配置”、“单请求单独配置”的互相配合
- 对于请求的响应结果,无法实现统一处理
我们解决了什么问题?
- 单厂商的Api,可以在一个类里面统一管理
- “站点地址”只需配置一次
- 各种配置实现了“系统统一配置”、“单厂商统一配置”、“单请求单独配置”的互相配合
- 请求的响应结果实现统一处理,也可以设置单个厂商或单个请求的个性化处理
- 提供了许多公共方法以供使用。如果公共方法无法满足需求,可以进行系统全局重写或单厂商重写
安装
执行安装
命令:php artisan gupo:http-client:install
安装做了些什么?
- 发布资源:
- Api访问出口类:
\App\Services\Api\ApiService
- 模块目录:
\App\Services\Api\Modules\
- Api抽象类:
\App\Services\Api\Support\BaseHttpClient
- 配置文件:
config/apis.php
- Api访问出口类:
- 将
\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
每个厂商的的api的"站点地址"与其他相关配置,请配置到config/apis.php
。获取配置时,用config('apis.xxx')
,例config('apis.wdPay.url')
。
注:配置文件中的内容,请从.env
中获取,例:env('WD_PAY_URL')
。
创建厂商Api文件
为单个厂商访问的所有Api在app\Services\Api\Modules\
目录下单独建一个Api类,继承抽象类\App\Services\Api\Support\BaseHttpClient
,类名建议为厂商名(如果厂商业务模块区分较为明确,也可以以厂商下的业务模块为单独建类的单位)。
例:
- 如果以厂商为建Api类的单位,厂商为"万达",建议类名为
WdApi
; - 例:如果以厂商与业务为建Api类的单位,厂商为"万达",业务为万达集团下的"统一支付",建议类名为
WdPayApi
;
Api类注册
注册Api单例访问出口
在\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单例
\Api::wdPay()
Api类开发
实现抽象内容
详见
\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根据不同逻辑变更
有的厂商的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);
}
访问Api请求接口
例:
$data = \Api->emr()->relay($hid, $url, $query)