分类 默认分类 下的文章

composer require guzzlehttp/guzzle 6.5.5
  1. 使用中间件

    // 堆栈
    $stack = HandlerStack::create();
    $stack->push(Middleware::mapRequest(function (RequestInterface $request) {
        // 加密请求参数
        // 在此处您可以实现加密逻辑
        // 这里的示例是将请求参数转换为JSON格式
        $encryptedBody = json_decode($request->getBody()->getContents(), true);
        // 创建一个新的请求,将加密后的参数设置为请求主体
        $request = $request->withBody(\GuzzleHttp\Psr7\stream_for($request->getBody()));
        return $request;
    }));
    $stack->push(Middleware::mapResponse(function (ResponseInterface $response) {
        // 在此处对响应内容进行解密
        // 这里的示例是将响应内容解密后返回
        $decryptedBody = json_decode($response->getBody(), true);
        // 创建一个新的响应,将解密后的内容设置为响应主体
        return $response->withBody(\GuzzleHttp\Psr7\stream_for(json_encode($decryptedBody)));
    }));

    $client = new Client([
        'handler'  => $stack,
        'base_uri' => '', // 请求的域名
        'headers'  => ['Content-Type' => 'application/json'],
        'timeout'  => 5,
    ]);

    $response = $client->post('/aa/bb', [
        'json' => ['a' => 'b'],
    ]);

    // 获取解密后的响应内容 body是个字符串,需要再json_decode
    $body = $response->getBody()->getContents();
  1. 并发请求 发起固定数量请求

     $t1       = microtime(true);
     $client   = new Client(['base_uri' => '']);
     $promises = [];
     $total    = 10;
     for ($i = 0; $i < $total; $i++) {
         $promises[] = $client->postAsync('/aa/bb', [
             'headers' => ['Content-Type' => 'application/json'],
             'json'    => $params,
             'timeout' => 1,
         ]);
     }
    
     try {
         $responses = Promise\Utils::unwrap($promises);
         $t2        = microtime(true);
         echo '请求次数 ' . $total . ' 耗时:' . ($t2 - $t1) . PHP_EOL;
         foreach ($responses as $res) {
             $body = $res->getBody()->getContents();
             dump($body);
         }
     } catch (\Exception $e) {
         // 如果有请求异常会抛出异常 : RequestException
         if ($e instanceof \GuzzleHttp\Exception\GuzzleException) {
             echo 'http error:' . $e->getMessage();
         } else {
             echo 'other error:' . $e->getMessage();
         }
     }
     // 等待请求完成,即使其中一些请求已经失败
     $responses = Promise\Utils::settle($promises)->wait();
     foreach ($responses as $key => $value) {
         if ($value['state'] === 'fulfilled') {
             $contents = $value['value']->getBody()->getContents();
         } elseif ($value['state'] === 'rejected') {
             
         }
     }
    
  2. 并发,多线程 发送不确定数量的请求

     $client   = new Client(['base_uri' => '']);    
     $requests = function ($total, $client, $params) {
         $uri = '/aa/bb';
         for ($i = 0; $i < $total; $i++) {
             yield function () use ($uri, $client, $params, $i) {
                 $params['i'] = $i;
                 return $client->requestAsync('POST', $uri, ['json' => $params]);
             };
         }
     };
    
     $return = [];
     $pool = new Pool($client, $requests($total, $client, $params), [
         'concurrency' => 5,
         'fulfilled'   => function ($response, $index) use (&$return) {
             $body           = $response->getBody()->getContents();
             $return[$index] = $body;
         },
         'rejected'    => function ($reason, $index) {
             echo 'rejected ' . $index . $reason . PHP_EOL;
         },
     ]);
    
     $promises = $pool->promise();
     $promises->wait();
     dump($return);
    

对外部变量进行写操作的时候,需要加上&引用,类似指针,不然外部变量不会实质更改。
新建promise、配置promise->then、返回promise三步走

一个封装的实现多个接口调用并发调用