添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

使用Guzzle发起异步请求

Guzzle是一个PHP的HTTP客户端,它在发起http请求时不仅可以同步发起,还可以异步发起。

$client = new Client();
$request = new Request('GET', 'http://www.baidu.com');
$promise = $client->sendAsync($request)->then(function ($response) {
	echo $response->getBody();
});
// todo something
echo 1;
$promise->wait();

PHP发起HTTP请求的几种方式

使用libcurl库,允许你与各种的服务器使用各种类型的协议进行连接和通讯。

stream

通过流的方式获取和发送远程文件,该功能需要ini配置allow_url_fopen=on。关于php的流更多参考PHP流(Stream)的概述与使用详解

在guzzle中可以兼容使用这两种的任意一种或者是用户自定义的http handler

function choose_handler()
    $handler = null;
    if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
        $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
    } elseif (function_exists('curl_exec')) {
        $handler = new CurlHandler();
    } elseif (function_exists('curl_multi_exec')) {
        $handler = new CurlMultiHandler();
    if (ini_get('allow_url_fopen')) {
        $handler = $handler
            ? Proxy::wrapStreaming($handler, new StreamHandler())
            : new StreamHandler();
    } elseif (!$handler) {
        throw new \RuntimeException('GuzzleHttp requires cURL, the '
            . 'allow_url_fopen ini setting, or a custom HTTP handler.');
    return $handler;

可以看出,guzzle会优先使用curl,然后选择使用stream,Proxy::wrapStreaming($handler, new StreamHandler()) 是一个流包装器。

    public static function wrapStreaming(
        callable $default,
        callable $streaming
        return function (RequestInterface $request, array $options) use ($default, $streaming) {
            return empty($options['stream'])
                ? $default($request, $options)
                : $streaming($request, $options);

什么是URI?URI的组成

URI,Uniform Resource Identifier,统一资源标识符。
scheme:[//[user:password@]host[:port]][/]path[?query][#fragment]
![1155692-865aa6e8904a0509.webp](https://imgconvert.csdnimg.cn/aHR0cHM6Ly9jZG4ubmxhcmsuY29tL3l1cXVlLzAvMjAyMC93ZWJwLzIzMDcwNC8xNTkxNjY2NzUxNzY3LWE5YWExZjdhLWQ0NmYtNGY4YS05N2Y1LTRjY2IzYzU0ZGMxYy53ZWJw?x-oss-process=image/format,png#align=left&display=inline&height=205&margin=[object Object]&name=1155692-865aa6e8904a0509.webp&originHeight=250&originWidth=918&size=15056&status=done&style=none&width=752)

请求的组装

Guzzle发起请求大致分为两个阶段,第一阶段负责将需要请求的uri组装成各种内部定义的类。

  • Client类:这是一个发起客户端的调用者,后续所有的调用需要基于这个负责的类实现,它负责提供一个 handler ,这是一个客户端发起http请求的句柄,其中Guzzle实现curl和stream调用的无感知就是在这里实现的,同时开发者也可以自定义请求协议。
// 根据系统当前状态,选择一个发起Http请求的协议的方法句柄
function choose_handler()
    $handler = null;
    if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
        $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
    } elseif (function_exists('curl_exec')) {
        $handler = new CurlHandler();
    } elseif (function_exists('curl_multi_exec')) {
        $handler = new CurlMultiHandler();
    if (ini_get('allow_url_fopen')) {
        $handler = $handler
            ? Proxy::wrapStreaming($handler, new StreamHandler())
            : new StreamHandler();
    } elseif (!$handler) {
        throw new \RuntimeException('GuzzleHttp requires cURL, the '
            . 'allow_url_fopen ini setting, or a custom HTTP handler.');
    return $handler;
  • Request类:负责定义一个uri
  • Promise类:这个类负责承载类请求发起前的各种准备工作完成后的结果,还包括两个回调(请求成功回调、请求失败回调),同时请求发起中的队列,延迟等处理也是在这个类里。

其中组装阶段最重要的方法是私有方法 private function transfer(RequestInterface $request, array $options) ,它负责将用户通过各种方法传入的uri和client类的各种属性组合,然后使用这些属性生成一个新的类 Promise 类。

请求的发起

Client的各种属性组装完成后就可以使用得到的Promise类发起http请求了,这里主要是通过一个 wait() 方法。

同步调用与异步调用

在同步方法内部的调用,同步方法是在内部组装好一个Promise之后立刻发起wait()调用。

    public function send(RequestInterface $request, array $options = [])
        $options[RequestOptions::SYNCHRONOUS] = true;
        return $this->sendAsync($request, $options)->wait();
wait的实现

wait() 方法的实现逻辑也很简单,递归调用wait()方法,直到result属性不是PromiseInterface实现类或者state不是pending,然后将结果逐层输出。这里说一下这个state的pending状态,这是一个PromiseInterface实现类的初始化状态,表示改实现类还没有完成,需要继续wait。

    public function wait($unwrap = true)
        $this->waitIfPending();
        $inner = $this->result instanceof PromiseInterface
            ? $this->result->wait($unwrap)
            : $this->result;
        if ($unwrap) {
            if ($this->result instanceof PromiseInterface
                || $this->state === self::FULFILLED
                return $inner;
            } else {
                // It's rejected so "unwrap" and throw an exception.
                throw exception_for($inner);

waitIfPending() : 如果promise类还处于pending状态就执行。主要是执行改实现类的waitFn方法。最外层promise执行完成后执行`queue()->run() ``` 这个方法内部循环执行队列内方法,直到队列为空。至此,Guzzle就能将组装进来的多个request,和各种方法执行完毕。

    private function waitIfPending()
        if ($this->state !== self::PENDING) {
            return;
        } elseif ($this->waitFn) {
            $this->invokeWaitFn();
        } elseif ($this->waitList) {
            $this->invokeWaitList();
        } else {
            // If there's not wait function, then reject the promise.
            $this->reject('Cannot wait on a promise that has '
                . 'no internal wait function. You must provide a wait '
                . 'function when constructing the promise to be able to '
                . 'wait on a promise.');
        queue()->run();
        if ($this->state === self::PENDING) {
            $this->reject('Invoking the wait callback did not resolve the promise');
    public function run()
        /** @var callable $task */
        while ($task = array_shift($this->queue)) {
            $task();
waitFn是什么

回到前面提到的transfer()函数。

$handler = $options['handler'];
// 返回一个promise类,这个类有一个属性是waitFn
return Promise\promise_for($handler($request, $options));

这里我们看 KaTeX parse error: Expected group after '_' at position 100: …是 HandleStack->_̲_invoke、Redirec…fn($request, options); fn就是HandleStack内部的Proxy包装的方法,无论使用哪种协议都会在各自的实现里实例化一个拥有waitFn的Promise的实例。

        // curl的实现
				$promise = new Promise(
            [$this, 'execute'],
            function () use ($id) {
                return $this->cancel($id);

由此可以直到waitFn方法就是各自协议的实现类的请求发起方法。then() 方法会将promise本身再封装一层promise,并将原先的waitFn和then()的回调方法打包进waitFnList属性里。

queue() 是的入队时机

当请求执行完成后依次调用 processMessages()、promise->resolve()、settle()、FulfilledPromise->then(),将请求结果插入队列。

        $queue->add(static function () use ($p, $value, $onFulfilled) {
            if ($p->getState() === self::PENDING) {
                try {
                    $p->resolve($onFulfilled($value));
                } catch (\Throwable $e) {
                    $p->reject($e);
                } catch (\Exception $e) {
                    $p->reject($e);
        });
                    Guzzle中的异步请求使用Guzzle发起异步请求Guzzle是一个PHP的HTTP客户端,它在发起http请求时不仅可以同步发起,还可以异步发起。$client = new Client();$request = new Request('GET', 'http://www.baidu.com');$promise = $client->sendAsync($request)->then(function ($response) {	echo $response->get
当前没有RateLimitProvider默认实现。
 use Concat \ Http \ Middleware \ RateLimiter ;
$ handlerStack -> push ( new RateLimiter ( $ rateLimitProvider ));
use Psr \ Http \ Message \ ResponseInterface ;
use Psr \ Http \ Message \ RequestInterface ;
use Concat \ Http \ Middleware \ RateLimitProvider ;
 * An object which manages rate d
 use GuzzleHttp \ Client ;
use Meng \ AsyncSoap \ Guzzle \ Factory ;
use Laminas \ Diactoros \ RequestFactory ;
use Laminas \ Diactoros \ StreamFactory ;
$ factory = new Factory ();
$ client = $ factory -> create ( new Client (), new StreamFactory (), new Req
设置header头
$http = new Client(['headers' => [
            "Access-Token" => '104231665f5749ecd79122edbcb89b55f7c55e40',
            "Content-type" => 'application/json'
发送post请求
        $response = $http->post(
作为经常需要使用到的API,项目可以添加GuzzleHttp扩展来使用,方便,快捷,全面;
这次我们项目开发使用的是laravel5.8,那么对于接口数据均是采用GuzzleHttp来获取的,文档有较为全面的使用介绍,本仙女这就只总结自己能用到的哟
二、封装使用
     * 请求接口,获取e信使用户需要完成的阅读任务
     * @param string $post 请求方...
				
// 文文档 [添加链接描述](https://guzzle-cn.readthedocs.io/zh_CN/) // POST require_once __DIR__ . '/vendor/autoload.php'; $client = new \GuzzleHttp\Client(); // 发送 application/x-www-form-urlencoded POST请求需要你传入 form_params 数组参数,数组内指定POST的字段。 $request = new \GuzzleHt
在处理业务时,我们总是会发起一个http请求,比如请求远程接口,或者下载一个文件.很显然,在PHP需要使用CURL,但是curl写起来实在是太不舒服了,又难写,也不易阅读.实际上PHP有很多扩展可以非常优雅的实现http请求,比如这篇文章要介绍的:guzzlehttp/guzzle. guzzle的特点: 接口简单:无论是一个简单地get请求,还是设置cookie,上传大文件,写起来都很简单 可以发起异步请求,并且用法与同步请求一致 使用PSR-7接口来请求、响应、分流,允许你使用其他兼容的PSR
https://guzzle-cn.readthedocs.io/zh_CN/latest/ https://packagist.org/packages/guzzlehttp/guzzle https://docs.guzzlephp.org/en/stable/ composer require guzzlehttp/guzzle 发送GET请求 require 'vendor/autoload.php'; use GuzzleHttp\Client; use GuzzleHttp\Pool;use GuzzleHttp\Client;//use GuzzleHttp\Psr7\Request;use Psr\Http\Message\ResponseInterface;use GuzzleHttp\Exception\RequestException; $client = new Client();$param = array( '... 接口简单:构建查询语句、POST请求、分流上传下载大文件、使用HTTP cookies、上传JSON数据等等。 发送同步或异步的请求均使用相同的接口。 使用PSR-7接口来请求、响应、分流,允许你使用其他兼容的PSR-7类库与Guzzle共同开发。 抽象了底层的HTTP传输,允许你改变环境以及其他的代码,如:对cURL与PHP的流或socket并非重度依赖,非阻塞事件循环。 间件系统允 1. 首先,确保你已经在项目安装了 Guzzle。你可以通过 Composer 进行安装,运行以下命令: composer require guzzlehttp/guzzle 2. 在你的 PHP 文件,引入 Guzzle 的命名空间: ```php use GuzzleHttp\Client; 3. 创建 Guzzle 的客户端对象: ```php $client = new Client(); 4. 使用 `$client` 对象发送 AJAX 请求。下面是一个发送 GET 请求的示例: ```php $response = $client->get('http://example.com/api/endpoint'); 如果需要发送 POST 请求,可以使用 `post()` 方法: ```php $response = $client->post('http://example.com/api/endpoint', [ 'form_params' => [ 'param1' => 'value1', 'param2' => 'value2', 5. 通过 `$response` 对象获取响应的内容: ```php $body = $response->getBody(); $content = $body->getContents(); 你可以根据需要对响应进行处理,例如解析 JSON 数据或提取特定的信息。 这就是使用 Guzzle 发送 AJAX 请求的基本步骤。记得根据自己的需求进行适当的配置和处理响应。