handlers-and-middleware.rst 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. =======================
  2. Handlers and Middleware
  3. =======================
  4. Guzzle clients use a handler and middleware system to send HTTP requests.
  5. Handlers
  6. ========
  7. A handler function accepts a ``Psr\Http\Message\RequestInterface`` and array of
  8. request options and returns a ``GuzzleHttp\Promise\PromiseInterface`` that is
  9. fulfilled with a ``Psr\Http\Message\ResponseInterface`` or rejected with an
  10. exception.
  11. You can provide a custom handler to a client using the ``handler`` option of
  12. a client constructor. It is important to understand that several request
  13. options used by Guzzle require that specific middlewares wrap the handler used
  14. by the client. You can ensure that the handler you provide to a client uses the
  15. default middlewares by wrapping the handler in the
  16. ``GuzzleHttp\HandlerStack::create(callable $handler = null)`` static method.
  17. .. code-block:: php
  18. use GuzzleHttp\Client;
  19. use GuzzleHttp\HandlerStack;
  20. use GuzzleHttp\Handler\CurlHandler;
  21. $handler = new CurlHandler();
  22. $stack = HandlerStack::create($handler); // Wrap w/ middleware
  23. $client = new Client(['handler' => $stack]);
  24. The ``create`` method adds default handlers to the ``HandlerStack``. When the
  25. ``HandlerStack`` is resolved, the handlers will execute in the following order:
  26. 1. Sending request:
  27. 1. ``http_errors`` - No op when sending a request. The response status code
  28. is checked in the response processing when returning a response promise up
  29. the stack.
  30. 2. ``allow_redirects`` - No op when sending a request. Following redirects
  31. occurs when a response promise is being returned up the stack.
  32. 3. ``cookies`` - Adds cookies to requests.
  33. 4. ``prepare_body`` - The body of an HTTP request will be prepared (e.g.,
  34. add default headers like Content-Length, Content-Type, etc.).
  35. 5. <send request with handler>
  36. 2. Processing response:
  37. 1. ``prepare_body`` - no op on response processing.
  38. 2. ``cookies`` - extracts response cookies into the cookie jar.
  39. 3. ``allow_redirects`` - Follows redirects.
  40. 4. ``http_errors`` - throws exceptions when the response status code ``>=``
  41. 300.
  42. When provided no ``$handler`` argument, ``GuzzleHttp\HandlerStack::create()``
  43. will choose the most appropriate handler based on the extensions available on
  44. your system.
  45. .. important::
  46. The handler provided to a client determines how request options are applied
  47. and utilized for each request sent by a client. For example, if you do not
  48. have a cookie middleware associated with a client, then setting the
  49. ``cookies`` request option will have no effect on the request.
  50. Middleware
  51. ==========
  52. Middleware augments the functionality of handlers by invoking them in the
  53. process of generating responses. Middleware is implemented as a higher order
  54. function that takes the following form.
  55. .. code-block:: php
  56. use Psr\Http\Message\RequestInterface;
  57. function my_middleware()
  58. {
  59. return function (callable $handler) {
  60. return function (RequestInterface $request, array $options) use ($handler) {
  61. return $handler($request, $options);
  62. };
  63. };
  64. }
  65. Middleware functions return a function that accepts the next handler to invoke.
  66. This returned function then returns another function that acts as a composed
  67. handler-- it accepts a request and options, and returns a promise that is
  68. fulfilled with a response. Your composed middleware can modify the request,
  69. add custom request options, and modify the promise returned by the downstream
  70. handler.
  71. Here's an example of adding a header to each request.
  72. .. code-block:: php
  73. use Psr\Http\Message\RequestInterface;
  74. function add_header($header, $value)
  75. {
  76. return function (callable $handler) use ($header, $value) {
  77. return function (
  78. RequestInterface $request,
  79. array $options
  80. ) use ($handler, $header, $value) {
  81. $request = $request->withHeader($header, $value);
  82. return $handler($request, $options);
  83. };
  84. };
  85. }
  86. Once a middleware has been created, you can add it to a client by either
  87. wrapping the handler used by the client or by decorating a handler stack.
  88. .. code-block:: php
  89. use GuzzleHttp\HandlerStack;
  90. use GuzzleHttp\Handler\CurlHandler;
  91. use GuzzleHttp\Client;
  92. $stack = new HandlerStack();
  93. $stack->setHandler(new CurlHandler());
  94. $stack->push(add_header('X-Foo', 'bar'));
  95. $client = new Client(['handler' => $stack]);
  96. Now when you send a request, the client will use a handler composed with your
  97. added middleware, adding a header to each request.
  98. Here's an example of creating a middleware that modifies the response of the
  99. downstream handler. This example adds a header to the response.
  100. .. code-block:: php
  101. use Psr\Http\Message\RequestInterface;
  102. use Psr\Http\Message\ResponseInterface;
  103. use GuzzleHttp\HandlerStack;
  104. use GuzzleHttp\Handler\CurlHandler;
  105. use GuzzleHttp\Client;
  106. function add_response_header($header, $value)
  107. {
  108. return function (callable $handler) use ($header, $value) {
  109. return function (
  110. RequestInterface $request,
  111. array $options
  112. ) use ($handler, $header, $value) {
  113. $promise = $handler($request, $options);
  114. return $promise->then(
  115. function (ResponseInterface $response) use ($header, $value) {
  116. return $response->withHeader($header, $value);
  117. }
  118. );
  119. };
  120. };
  121. }
  122. $stack = new HandlerStack();
  123. $stack->setHandler(new CurlHandler());
  124. $stack->push(add_response_header('X-Foo', 'bar'));
  125. $client = new Client(['handler' => $stack]);
  126. Creating a middleware that modifies a request is made much simpler using the
  127. ``GuzzleHttp\Middleware::mapRequest()`` middleware. This middleware accepts
  128. a function that takes the request argument and returns the request to send.
  129. .. code-block:: php
  130. use Psr\Http\Message\RequestInterface;
  131. use GuzzleHttp\HandlerStack;
  132. use GuzzleHttp\Handler\CurlHandler;
  133. use GuzzleHttp\Client;
  134. use GuzzleHttp\Middleware;
  135. $stack = new HandlerStack();
  136. $stack->setHandler(new CurlHandler());
  137. $stack->push(Middleware::mapRequest(function (RequestInterface $request) {
  138. return $request->withHeader('X-Foo', 'bar');
  139. }));
  140. $client = new Client(['handler' => $stack]);
  141. Modifying a response is also much simpler using the
  142. ``GuzzleHttp\Middleware::mapResponse()`` middleware.
  143. .. code-block:: php
  144. use Psr\Http\Message\ResponseInterface;
  145. use GuzzleHttp\HandlerStack;
  146. use GuzzleHttp\Handler\CurlHandler;
  147. use GuzzleHttp\Client;
  148. use GuzzleHttp\Middleware;
  149. $stack = new HandlerStack();
  150. $stack->setHandler(new CurlHandler());
  151. $stack->push(Middleware::mapResponse(function (ResponseInterface $response) {
  152. return $response->withHeader('X-Foo', 'bar');
  153. }));
  154. $client = new Client(['handler' => $stack]);
  155. HandlerStack
  156. ============
  157. A handler stack represents a stack of middleware to apply to a base handler
  158. function. You can push middleware to the stack to add to the top of the stack,
  159. and unshift middleware onto the stack to add to the bottom of the stack. When
  160. the stack is resolved, the handler is pushed onto the stack. Each value is
  161. then popped off of the stack, wrapping the previous value popped off of the
  162. stack.
  163. .. code-block:: php
  164. use Psr\Http\Message\RequestInterface;
  165. use GuzzleHttp\HandlerStack;
  166. use GuzzleHttp\Middleware;
  167. use GuzzleHttp\Client;
  168. $stack = new HandlerStack();
  169. $stack->setHandler(\GuzzleHttp\choose_handler());
  170. $stack->push(Middleware::mapRequest(function (RequestInterface $r) {
  171. echo 'A';
  172. return $r;
  173. });
  174. $stack->push(Middleware::mapRequest(function (RequestInterface $r) {
  175. echo 'B';
  176. return $r;
  177. });
  178. $stack->push(Middleware::mapRequest(function (RequestInterface $r) {
  179. echo 'C';
  180. return $r;
  181. });
  182. $client->request('GET', 'http://httpbin.org/');
  183. // echoes 'ABC';
  184. $stack->unshift(Middleware::mapRequest(function (RequestInterface $r) {
  185. echo '0';
  186. return $r;
  187. });
  188. $client = new Client(['handler' => $stack]);
  189. $client->request('GET', 'http://httpbin.org/');
  190. // echoes '0ABC';
  191. You can give middleware a name, which allows you to add middleware before
  192. other named middleware, after other named middleware, or remove middleware
  193. by name.
  194. .. code-block:: php
  195. use Psr\Http\Message\RequestInterface;
  196. use GuzzleHttp\Middleware;
  197. // Add a middleware with a name
  198. $stack->push(Middleware::mapRequest(function (RequestInterface $r) {
  199. return $r->withHeader('X-Foo', 'Bar');
  200. }, 'add_foo');
  201. // Add a middleware before a named middleware (unshift before).
  202. $stack->before('add_foo', Middleware::mapRequest(function (RequestInterface $r) {
  203. return $r->withHeader('X-Baz', 'Qux');
  204. }, 'add_baz');
  205. // Add a middleware after a named middleware (pushed after).
  206. $stack->after('add_baz', Middleware::mapRequest(function (RequestInterface $r) {
  207. return $r->withHeader('X-Lorem', 'Ipsum');
  208. });
  209. // Remove a middleware by name
  210. $stack->remove('add_foo');
  211. Creating a Handler
  212. ==================
  213. As stated earlier, a handler is a function accepts a
  214. ``Psr\Http\Message\RequestInterface`` and array of request options and returns
  215. a ``GuzzleHttp\Promise\PromiseInterface`` that is fulfilled with a
  216. ``Psr\Http\Message\ResponseInterface`` or rejected with an exception.
  217. A handler is responsible for applying the following :doc:`request-options`.
  218. These request options are a subset of request options called
  219. "transfer options".
  220. - :ref:`cert-option`
  221. - :ref:`connect_timeout-option`
  222. - :ref:`debug-option`
  223. - :ref:`delay-option`
  224. - :ref:`decode_content-option`
  225. - :ref:`expect-option`
  226. - :ref:`proxy-option`
  227. - :ref:`sink-option`
  228. - :ref:`timeout-option`
  229. - :ref:`ssl_key-option`
  230. - :ref:`stream-option`
  231. - :ref:`verify-option`