接口开发是否有必要在调用接口的时候每次都重新 new GuzzleClient()

下面这 2 个有区别吗

  1. new GuzzleClient 创建实例每次调用同一平台接口都用这个, 我记得 new class 是有性能消耗的,貌似也不大。
  2. 每次请求都 new GuzzleClient, 每次请求都不影响结果,每次都需要组装 options 参数

你们用那种嘞? 有区别吗

目的:谋求更优雅的代码

世界上最遥远的距离不是生与死,而是你亲手制造的BUG就在你眼前,你却怎么都找不到ta。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L01 基础入门》
我们将带你从零开发一个项目并部署到线上,本课程教授 Web 开发中专业、实用的技能,如 Git 工作流、Laravel Mix 前端工作流等。
讨论数量: 25

我一般这样
$client = new CLient($options);
$client->request();
$client->request();

我记不得多次请求是否会有影响了,如果有就
$client = new CLient($options);
(clone $client)->request();
(clone $client)->request();

3个月前 评论
kis龍 (楼主) 2个月前
kis龍 (楼主) 3个月前
qianfan 3个月前
kis龍 (楼主) 2个月前
qianfan 2个月前
kis龍 (楼主) 2个月前

类的实例化确实是会消耗性能,所有才有单例模式,我是直接用Http Facade。

3个月前 评论
kis龍 (楼主) 3个月前

工厂模式的目的,尽可能保证类实例化的独立性,避免单例模式因为上下文带来的影响。

  • 从业务角度看:同时间http多次请求同一个接口或不同接口(环境配置相同),减少性能开销的方式应该是并发处理。
  • 从架构角度看:以fpm为例,在一个fpm生命周期内,应该考虑的是复用http链接,这样每次请求都不需要新建http链接,常见的处理方式:持久化链接,pfsockopen,或者使用第三方工具例如go实现。
3个月前 评论

都用php就别纠结这个性能了

3个月前 评论
kis龍 (楼主) 3个月前
博学多才的走停 2个月前

两种方式,
1是直接使用单例,
2是使用laravel容器托管。

class MTClient
{

    use CookieUtil;
    protected Client $client;
    protected string $host = "localhost";
    protected static Client $inc = null;

    public static function getInstance(): Client
    {
        if (self::$inc === null) {
            self::$inc = new self();
        }
        return self::$inc;
    }
/**
逻辑代码省略
*/
}

使用方式是

MTClient::getInstance()->XXXX()

第二种方式,就是用laravel的app函数

$server = app(XXX::class);
$server->xxx();

这个函数就是创建一个单例全局托管的。
他的源码是

if (! function_exists('app')) {
    /**
     * Get the available container instance.
     *
     * @param  string|null  $abstract
     * @param  array  $parameters
     * @return \Illuminate\Contracts\Foundation\Application|\Illuminate\Foundation\Application|mixed
     */
    function app($abstract = null, array $parameters = [])
    {
        if (is_null($abstract)) {
            return Container::getInstance();
        }

        return Container::getInstance()->make($abstract, $parameters);
    }
}

当然我其实觉得这些还都算小问题,主要是client的封装是否便于业务使用。我的一个client大概这样。

<?php


namespace App\RemoteClient;

use Faker\Factory;
use GuzzleHttp\Client;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Cookie\SetCookie;
use GuzzleHttp\RequestOptions;


/**
 * Class MTClient
 * localhost gthh
 * @package App\RemoteClient
 */
class MTClient
{

    use CookieUtil;
    protected Client $client;
    protected string $host = "localhost";

    public function __construct()
    {
        $base_uri     = 'http://localhost:8080';
        $this->client = new Client([
            'base_uri'    => $base_uri,
            'timeout'     => 10.0,
            'http_errors' => false,
            'verify'      => false,
            'cookies'     => $this->getCookieFromDomain('localhost'),
            'headers'     => [
                'User-Agent'   => 'User-Agent:Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
                "Connection"   => "keep-alive",
                "Content-Type" => "application/json",
                "NOT"          => 1
            ],
        ]);
    }

    public function __destruct()
    {
        $this->saveCookie();
    }


    public function xGet(string $uri, array $params)
    {
        $response = $this->client->request('POST', $uri, [
            RequestOptions::FORM_PARAMS => $params
        ]);

        $body = (string)$response->getBody();

        echo ($body) . PHP_EOL;

        return $body;
    }

    protected function pJson(string $uri, array $json): string
    {
        $response = $this->client->request('POST', $uri, [
            RequestOptions::JSON => $json
        ]);

        $body = (string)$response->getBody();

        echo ($body) . PHP_EOL;

        return $body;
    }

    public function reg(): string
    {
        $faker = Factory::create();
        return $this->pJson("api/reg", [
            "email"    => microtime(true).$faker->email,
            "userName" => $faker->userName,
            "passWord" => '123456',//$faker->password,
            "nickName" => $faker->name,
        ]);
    }

    public function login():string
    {
        return $this->pJson("api/login", [
            "userName" => 'dicki.andres',
            "passWord" => '123456',
        ]);
    }

    public function aApiNeedJwt($token):string
    {
        $response = $this->client->request('POST', "api/AApiNeedJwt", [
            RequestOptions::JSON => [

            ],
            RequestOptions::HEADERS=>[
                "x-token"=>$token,
            ]
        ]);

        $body = (string)$response->getBody();

        echo ($body) . PHP_EOL;

        return $body;
    }

}
3个月前 评论
lovewei 3个月前

有reset 就用单例,没有,为了不影响上下文就每次都new

3个月前 评论

代码性能消耗是其次,并发高的话频繁new Client 会有连接数的问题

3个月前 评论
JeffreyBool 3个月前

越来越神了……你们都是啥业务啊,还 new 实例的损耗都来了,且不说随便一个类实例化,正常场景下就算 new Client 又能有多大的开销来的。

还有那个 new Client 影响连接数的,真看过 Client 里面的实现嘛,连接又不是凭空建立来的……


不过对于 FPM 模式而言,对外部的 HTTP 的请求,连接确实比较耗时,但是这跟 new Client 无关。

一个好消息是 PHP 团队在前不久刚投票通过接受(Accepted)了一个 RFC,在下一个的小版本(minor)中将新增一个 curl_share_init(?array $share_options, ?string $persistent_id) 来共享 curl 句柄,从而避免 FPM 下 cURL 的连接浪费(现在就有这个 curl_share_init 函数,这次的 RFC 是增强)。

3个月前 评论
kis龍 (楼主) 3个月前
若只如初见 3个月前

GuzzleClient 是线程安全的,并且设计上是允许被多次使用的。

1个月前 评论

生产项目实测,区别确实很大的,在qps2W的情况下, 复用实列之后cpu下降很多

4周前 评论
kis龍 (楼主) 3周前

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!