处理程序和中间件

Guzzle客户端使用一个处理程序和中间件系统来发送HTTP请求。

处理程序

一个处理函数接受一个Psr\HttpMessage\RequestInterface和数组的 请求选项,并返回一个GuzzleHttp\Promise\PromiseInterface,该请求被 响应Psr\Http\Message\ResponseInterface或拒绝一个异常。 异常。

你可以使用handler的选项为客户端提供一个自定义处理程序。 客户端构造函数的选项。重要的是要明白,Guzzle使用的几个请求 选项需要特定的中间件来包住客户端使用的处理程序。 的处理程序。你可以确保你提供给客户端的处理程序使用的是 默认的中间件,方法是将处理程序包裹在 GuzzleHttp\HandlerStack::create(callable $handler = null)静态方法。

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;

$handler = new CurlHandler();
$stack = HandlerStack::create($handler); // Wrap w/ middleware
$client = new Client(['handler' => $stack]);

create方法将默认的处理程序添加到HandlerStack。当HandlerStack被解析时,这些处理程序将按照以下顺序执行。

  1. 发出请求。
  1. http_errors - 发送请求时没有操作。响应状态代码 响应状态代码在响应处理过程中被检查,当向上返回一个响应承诺时 栈中返回响应承诺时,在响应处理中检查响应状态代码。
  2. allow_redirects - 发送请求时没有操作。跟随重定向 发生在响应承诺被向上堆栈返回时。
  3. cookies - 将cookies添加到请求。
  4. prepare_body - HTTP请求的正文将被准备好(例如。 添加默认的头信息,如Content-Length、Content-Type等)。
  5. <用处理程序发送请求>。
  1. 处理答复。
  1. prepare_body - 响应处理上没有操作。
  2. cookies - 将响应的cookies提取到cookie jar。
  3. allow_redirects - 跟随重定向。
  4. http_errors - 当响应状态代码>= 抛出异常。 400.

当没有提供$handler参数时,GuzzleHttp\HandlerStack::create()

重要的是

提供给客户端的处理程序决定了如何应用请求选项 并利用客户端发送的每个请求。例如,如果你没有 有一个与客户端相关的cookie中间件,那么设置 cookies 请求选项将对请求没有影响。

中间件

中间件通过在生成响应的过程中调用处理程序来增强它们的功能。 生成响应的过程中调用处理程序,从而增强处理程序的功能。中间件被实现为一个高阶 函数,其形式如下。

use Psr\Http\Message\RequestInterface;

function my_middleware()
{
    return function (callable $handler) {
        return function (RequestInterface $request, array $options) use ($handler) {
            return $handler($request, $options);
        };
    };
}

中间件函数返回一个接受下一个处理程序的函数来调用。 这个返回的函数然后返回另一个函数,作为一个组成的 处理程序--它接受一个请求和选项,并返回一个承诺,该承诺将通过一个响应来实现。 响应的承诺。你组成的中间件可以修改请求。 添加自定义的请求选项,并修改由下游处理程序返回的承诺。 处理程序返回的承诺。

下面是一个为每个请求添加头的例子。

use Psr\Http\Message\RequestInterface;

function add_header($header, $value)
{
    return function (callable $handler) use ($header, $value) {
        return function (
            RequestInterface $request,
            array $options
        ) use ($handler, $header, $value) {
            $request = $request->withHeader($header, $value);
            return $handler($request, $options);
        };
    };
}

一旦创建了一个中间件,你可以通过包装客户端使用的处理程序或装饰处理程序栈来将其添加到客户端。

use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Client;

$stack = new HandlerStack();
$stack->setHandler(new CurlHandler());
$stack->push(add_header('X-Foo', 'bar'));
$client = new Client(['handler' => $stack]);

现在,当你发送一个请求时,客户端将使用一个由你添加的中间件组成的处理程序,为每个请求添加一个头。

下面是一个创建中间件的例子,它修改了下游处理程序的响应。这个例子在响应中添加了一个头。

use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Client;

function add_response_header($header, $value)
{
    return function (callable $handler) use ($header, $value) {
        return function (
            RequestInterface $request,
            array $options
        ) use ($handler, $header, $value) {
            $promise = $handler($request, $options);
            return $promise->then(
                function (ResponseInterface $response) use ($header, $value) {
                    return $response->withHeader($header, $value);
                }
            );
        };
    };
}

$stack = new HandlerStack();
$stack->setHandler(new CurlHandler());
$stack->push(add_response_header('X-Foo', 'bar'));
$client = new Client(['handler' => $stack]);

创建一个修改请求的中间件,使用以下方法会变得更加简单 GuzzleHttp\Middleware::mapRequest() 中间件。这个中间件接受 一个函数,该函数接收请求参数并返回要发送的请求。

use Psr\Http\Message\RequestInterface;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Client;
use GuzzleHttp\Middleware;

$stack = new HandlerStack();
$stack->setHandler(new CurlHandler());

$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
    return $request->withHeader('X-Foo', 'bar');
}));

$client = new Client(['handler' => $stack]);

使用GuzzleHttpMiddleware::mapResponse()中间件,修改响应也更简单。

use Psr\Http\Message\ResponseInterface;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Handler\CurlHandler;
use GuzzleHttp\Client;
use GuzzleHttp\Middleware;

$stack = new HandlerStack();
$stack->setHandler(new CurlHandler());

$stack->push(Middleware::mapResponse(function (ResponseInterface $response) {
    return $response->withHeader('X-Foo', 'bar');
}));

$client = new Client(['handler' => $stack]);

HandlerStack

一个处理程序栈表示一个中间件的栈,适用于一个基本处理程序的 函数。你可以把中间件推到堆栈中,添加到堆栈的顶部。 并把中间件移到堆栈上,以添加到堆栈的底部。当 栈被解决时,处理程序被推到栈上。每个值都被 然后从堆栈中弹出,包住从堆栈中弹出的前一个值。 栈的前一个值。

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;
use GuzzleHttp\Utils;
use Psr\Http\Message\RequestInterface;

$stack = new HandlerStack();
$stack->setHandler(Utils::chooseHandler());

$stack->push(Middleware::mapRequest(function (RequestInterface $r) {
    echo 'A';
    return $r;
}));

$stack->push(Middleware::mapRequest(function (RequestInterface $r) {
    echo 'B';
    return $r;
}));

$stack->push(Middleware::mapRequest(function (RequestInterface $r) {
    echo 'C';
    return $r;
}));

$client->request('GET', 'http://httpbin.org/');
// echoes 'ABC';

$stack->unshift(Middleware::mapRequest(function (RequestInterface $r) {
    echo '0';
    return $r;
}));

$client = new Client(['handler' => $stack]);
$client->request('GET', 'http://httpbin.org/');
// echoes '0ABC';

你可以给中间件一个名字,这样你就可以在其他被命名的中间件之前添加中间件,在其他被命名的中间件之后添加,或者删除中间件。 添加到其他命名的中间件之前,或添加到其他命名的中间件之后,或通过名称删除中间件 的名称。

use Psr\Http\Message\RequestInterface;
use GuzzleHttp\Middleware;

// Add a middleware with a name
$stack->push(Middleware::mapRequest(function (RequestInterface $r) {
    return $r->withHeader('X-Foo', 'Bar');
}, 'add_foo'));

// Add a middleware before a named middleware (unshift before).
$stack->before('add_foo', Middleware::mapRequest(function (RequestInterface $r) {
    return $r->withHeader('X-Baz', 'Qux');
}, 'add_baz'));

// Add a middleware after a named middleware (pushed after).
$stack->after('add_baz', Middleware::mapRequest(function (RequestInterface $r) {
    return $r->withHeader('X-Lorem', 'Ipsum');
}));

// Remove a middleware by name
$stack->remove('add_foo');

创建一个处理程序

如前所述,处理程序是一个函数,接受一个 Psr\Http\Message\RequestInterface 和请求选项的数组,并返回 一个GuzzleHttp\Promise\PromiseInterface,它被满足于一个 Psr\Http\Message\ResponseInterface或以异常拒绝。

一个处理程序负责应用以下请求选项。 这些请求选项是请求选项的一个子集,称为 "传输选项"。