1
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Transitional//EN' 'http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd'><html lang="en" xmlns="http://www.w3.org/1999/xhtml">
3
<title>Twisted Documentation:
4
Using the Twisted Web Client
6
<link href="stylesheet.css" rel="stylesheet" type="text/css"/>
11
Using the Twisted Web Client
13
<div class="toc"><ol><li><a href="#auto0">
15
</a></li><ul><li><a href="#auto1">
17
</a></li></ul><li><a href="#auto2">
19
</a></li><ul><li><a href="#auto3">Issuing Requests</a></li><li><a href="#auto4">
21
</a></li></ul><li><a href="#auto5">
29
<a name="auto0"/></h2>
32
This document describes how to use the HTTP client included in Twisted
33
Web. After reading it, you should be able to make HTTP requests using
34
Twisted Web. You will be able to specify the request method, headers,
35
and body and you will be able to retrieve the response code, headers, and
41
<a name="auto1"/></h3>
44
This document assumes that you are familiar with <a href="../../core/howto/defer.html" shape="rect">Deferreds and Failures</a>, and <a href="../../core/howto/producers.html" shape="rect">producers and consumers</a>.
45
It also assumes you are familiar with the basic concepts of HTTP, such
46
as requests and responses, methods, headers, and message bodies.
51
<a name="auto2"/></h2>
53
<h3>Issuing Requests<a name="auto3"/></h3>
56
The <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.client.Agent.html" title="twisted.web.client.Agent">twisted.web.client.Agent</a></code> class is the entry
57
point into the client API. Requests are issued using the <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.client.Agent.request.html" title="twisted.web.client.Agent.request">request</a></code> method, which
58
takes as parameters a request method, a request URI, the request headers,
59
and an object which can produce the request body (if there is to be one).
60
The agent is responsible for connection setup. Because of this, it
61
requires a reactor as an argument to its initializer. An example of
62
creating an agent and issuing a request using it might look like this:
65
<div class="py-listing"><pre><p class="py-linenumber"> 1
86
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
87
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">client</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Agent</span>
88
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">http_headers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Headers</span>
90
<span class="py-src-variable">agent</span> = <span class="py-src-variable">Agent</span>(<span class="py-src-variable">reactor</span>)
92
<span class="py-src-variable">d</span> = <span class="py-src-variable">agent</span>.<span class="py-src-variable">request</span>(
93
<span class="py-src-string">'GET'</span>,
94
<span class="py-src-string">'http://example.com/'</span>,
95
<span class="py-src-variable">Headers</span>({<span class="py-src-string">'User-Agent'</span>: [<span class="py-src-string">'Twisted Web Client Example'</span>]}),
96
<span class="py-src-variable">None</span>)
98
<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbResponse</span>(<span class="py-src-parameter">ignored</span>):
99
<span class="py-src-keyword">print</span> <span class="py-src-string">'Response received'</span>
100
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cbResponse</span>)
102
<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbShutdown</span>(<span class="py-src-parameter">ignored</span>):
103
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
104
<span class="py-src-variable">d</span>.<span class="py-src-variable">addBoth</span>(<span class="py-src-variable">cbShutdown</span>)
106
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
107
</pre><div class="caption">
108
Issue a request with an Agent
109
- <a href="listings/client/request.py"><span class="filename">listings/client/request.py</span></a></div></div>
112
As may be obvious, this issues a new <em>GET</em> request for <em>/</em>
113
to the web server on <code>example.com</code>. <code>Agent</code> is
114
responsible for resolving the hostname into an IP address and connecting
115
to it on port 80. It is also responsible for cleaning up the connection
116
afterwards. This code sends a request which includes one custom header,
117
<em>User-Agent</em>. The last argument passed to <code>Agent.request</code> is
118
<code>None</code>, though, so the request has no body.
122
Sending a request which does include a body requires passing an object
123
providing <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.iweb.IBodyProducer.html" title="twisted.web.iweb.IBodyProducer">twisted.web.iweb.IBodyProducer</a></code>
124
to <code>Agent.request</code>. This interface extends the more general
125
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IPushProducer.html" title="twisted.internet.interfaces.IPushProducer">IPushProducer</a></code>
126
by adding a new <code>length</code> attribute and adding several
127
constraints to the way the producer and consumer interact.
132
The length attribute must be a non-negative integer or the constant
133
<code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.iweb.UNKNOWN_LENGTH.html" title="twisted.web.iweb.UNKNOWN_LENGTH">twisted.web.iweb.UNKNOWN_LENGTH</a></code>. If the
134
length is known, it will be used to specify the value for the
135
<em>Content-Length</em> header in the request. If the length is
136
unknown the attribute should be set to <code>UNKNOWN_LENGTH</code>.
137
Since more servers support <em>Content-Length</em>, if a length can be
138
provided it should be.
142
An additional method is required on <code>IEntityBodyProvider</code>
143
implementations: <code>startProducing</code>. This method is used to
144
associate a consumer with the producer. It should return a
145
<code>Deferred</code> which fires when all data has been produced.
149
<code>IEntityBodyProvider</code> implementations should never call the
150
consumer's <code>unregisterProducer</code> method. Instead, when it
151
has produced all of the data it is going to produce, it should only
152
fire the <code>Deferred</code> returned by <code>startProducing</code>.
157
For additional details about the requirements of <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.iweb.IBodyProducer.html" title="twisted.web.iweb.IBodyProducer">IBodyProducer</a></code> implementations, see
158
the API documentation.
162
Here's a simple <code>IEntityBodyProvider</code> implementation which
163
writes an in-memory string to the consumer:
166
<div class="py-listing"><pre><p class="py-linenumber"> 1
187
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">zope</span>.<span class="py-src-variable">interface</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">implements</span>
189
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">defer</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">succeed</span>
190
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">iweb</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">IBodyProducer</span>
192
<span class="py-src-keyword">class</span> <span class="py-src-identifier">StringProducer</span>(<span class="py-src-parameter">object</span>):
193
<span class="py-src-variable">implements</span>(<span class="py-src-variable">IBodyProducer</span>)
195
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">body</span>):
196
<span class="py-src-variable">self</span>.<span class="py-src-variable">body</span> = <span class="py-src-variable">body</span>
197
<span class="py-src-variable">self</span>.<span class="py-src-variable">length</span> = <span class="py-src-variable">len</span>(<span class="py-src-variable">body</span>)
199
<span class="py-src-keyword">def</span> <span class="py-src-identifier">startProducing</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">consumer</span>):
200
<span class="py-src-variable">consumer</span>.<span class="py-src-variable">write</span>(<span class="py-src-variable">self</span>.<span class="py-src-variable">body</span>)
201
<span class="py-src-keyword">return</span> <span class="py-src-variable">succeed</span>(<span class="py-src-variable">None</span>)
203
<span class="py-src-keyword">def</span> <span class="py-src-identifier">pauseProducing</span>(<span class="py-src-parameter">self</span>):
204
<span class="py-src-keyword">pass</span>
206
<span class="py-src-keyword">def</span> <span class="py-src-identifier">stopProducing</span>(<span class="py-src-parameter">self</span>):
207
<span class="py-src-keyword">pass</span>
208
</pre><div class="caption">
209
A string-based body producer.
210
- <a href="listings/client/stringprod.py"><span class="filename">listings/client/stringprod.py</span></a></div></div>
213
This producer can be used to issue a request with a body:
216
<div class="py-listing"><pre><p class="py-linenumber"> 1
240
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
241
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">client</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Agent</span>
242
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">http_headers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Headers</span>
244
<span class="py-src-keyword">from</span> <span class="py-src-variable">stringprod</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">StringProducer</span>
246
<span class="py-src-variable">agent</span> = <span class="py-src-variable">Agent</span>(<span class="py-src-variable">reactor</span>)
247
<span class="py-src-variable">body</span> = <span class="py-src-variable">StringProducer</span>(<span class="py-src-string">"hello, world"</span>)
248
<span class="py-src-variable">d</span> = <span class="py-src-variable">agent</span>.<span class="py-src-variable">request</span>(
249
<span class="py-src-string">'GET'</span>,
250
<span class="py-src-string">'http://example.com/'</span>,
251
<span class="py-src-variable">Headers</span>({<span class="py-src-string">'User-Agent'</span>: [<span class="py-src-string">'Twisted Web Client Example'</span>],
252
<span class="py-src-string">'Content-Type'</span>: [<span class="py-src-string">'text/x-greeting'</span>]}),
253
<span class="py-src-variable">body</span>)
255
<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbResponse</span>(<span class="py-src-parameter">ignored</span>):
256
<span class="py-src-keyword">print</span> <span class="py-src-string">'Response received'</span>
257
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cbResponse</span>)
259
<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbShutdown</span>(<span class="py-src-parameter">ignored</span>):
260
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
261
<span class="py-src-variable">d</span>.<span class="py-src-variable">addBoth</span>(<span class="py-src-variable">cbShutdown</span>)
263
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
264
</pre><div class="caption">
265
Issue a request with a body.
266
- <a href="listings/client/sendbody.py"><span class="filename">listings/client/sendbody.py</span></a></div></div>
270
<a name="auto4"/></h3>
273
So far, the examples have demonstrated how to issue a request. However,
274
they have ignored the response, except for showing that it is a
275
<code>Deferred</code> which seems to fire when the response has been
276
received. Next we'll cover what that response is and how to interpret
281
<code>Agent.request</code>, as with most <code>Deferred</code>-returning
282
APIs, can return a <code>Deferred</code> which fires with a
283
<code>Failure</code>. If the request fails somehow, this will be
284
reflected with a failure. This may be due to a problem looking up the
285
host IP address, or it may be because the HTTP server is not accepting
286
connections, or it may be because of a problem parsing the response, or
287
any other problem which arises which prevents the response from being
288
received. It does <em>not</em> include responses with an error status.
292
If the request succeeds, though, the <code>Deferred</code> will fire with
293
a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.client.Response.html" title="twisted.web.client.Response">Response</a></code>. This
294
happens as soon as all the response headers have been received. It
295
happens before any of the response body, if there is one, is processed.
296
The <code>Response</code> object has several attributes giving the
297
response information: its code, version, phrase, and headers, as well as
298
the length of the body to expect. The <code>Response</code> object also
299
has a method which makes the response body available: <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web._newclient.Response.deliverBody.deliverBody.html" title="twisted.web._newclient.Response.deliverBody.deliverBody">deliverBody</a></code>.
300
Using the attributes of the response object and this method, here's an
301
example which displays part of the response to a request:
304
<div class="py-listing"><pre><p class="py-linenumber"> 1
351
</p><span class="py-src-keyword">from</span> <span class="py-src-variable">pprint</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">pformat</span>
353
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">reactor</span>
354
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">defer</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Deferred</span>
355
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">internet</span>.<span class="py-src-variable">protocol</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Protocol</span>
356
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">client</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Agent</span>
357
<span class="py-src-keyword">from</span> <span class="py-src-variable">twisted</span>.<span class="py-src-variable">web</span>.<span class="py-src-variable">http_headers</span> <span class="py-src-keyword">import</span> <span class="py-src-variable">Headers</span>
359
<span class="py-src-keyword">class</span> <span class="py-src-identifier">BeginningPrinter</span>(<span class="py-src-parameter">Protocol</span>):
360
<span class="py-src-keyword">def</span> <span class="py-src-identifier">__init__</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">finished</span>):
361
<span class="py-src-variable">self</span>.<span class="py-src-variable">finished</span> = <span class="py-src-variable">finished</span>
362
<span class="py-src-variable">self</span>.<span class="py-src-variable">remaining</span> = <span class="py-src-number">1024</span> * <span class="py-src-number">10</span>
364
<span class="py-src-keyword">def</span> <span class="py-src-identifier">dataReceived</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">bytes</span>):
365
<span class="py-src-keyword">if</span> <span class="py-src-variable">self</span>.<span class="py-src-variable">remaining</span>:
366
<span class="py-src-variable">display</span> = <span class="py-src-variable">bytes</span>[:<span class="py-src-variable">self</span>.<span class="py-src-variable">remaining</span>]
367
<span class="py-src-keyword">print</span> <span class="py-src-string">'Some data received:'</span>
368
<span class="py-src-keyword">print</span> <span class="py-src-variable">display</span>
369
<span class="py-src-variable">self</span>.<span class="py-src-variable">remaining</span> -= <span class="py-src-variable">len</span>(<span class="py-src-variable">display</span>)
371
<span class="py-src-keyword">def</span> <span class="py-src-identifier">connectionLost</span>(<span class="py-src-parameter">self</span>, <span class="py-src-parameter">reason</span>):
372
<span class="py-src-keyword">print</span> <span class="py-src-string">'Finished receiving body:'</span>, <span class="py-src-variable">reason</span>.<span class="py-src-variable">getErrorMessage</span>()
373
<span class="py-src-variable">self</span>.<span class="py-src-variable">finished</span>.<span class="py-src-variable">callback</span>(<span class="py-src-variable">None</span>)
375
<span class="py-src-variable">agent</span> = <span class="py-src-variable">Agent</span>(<span class="py-src-variable">reactor</span>)
376
<span class="py-src-variable">d</span> = <span class="py-src-variable">agent</span>.<span class="py-src-variable">request</span>(
377
<span class="py-src-string">'GET'</span>,
378
<span class="py-src-string">'http://example.com/'</span>,
379
<span class="py-src-variable">Headers</span>({<span class="py-src-string">'User-Agent'</span>: [<span class="py-src-string">'Twisted Web Client Example'</span>]}),
380
<span class="py-src-variable">None</span>)
382
<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbRequest</span>(<span class="py-src-parameter">response</span>):
383
<span class="py-src-keyword">print</span> <span class="py-src-string">'Response version:'</span>, <span class="py-src-variable">response</span>.<span class="py-src-variable">version</span>
384
<span class="py-src-keyword">print</span> <span class="py-src-string">'Response code:'</span>, <span class="py-src-variable">response</span>.<span class="py-src-variable">code</span>
385
<span class="py-src-keyword">print</span> <span class="py-src-string">'Response phrase:'</span>, <span class="py-src-variable">response</span>.<span class="py-src-variable">phrase</span>
386
<span class="py-src-keyword">print</span> <span class="py-src-string">'Response headers:'</span>
387
<span class="py-src-keyword">print</span> <span class="py-src-variable">pformat</span>(<span class="py-src-variable">list</span>(<span class="py-src-variable">response</span>.<span class="py-src-variable">headers</span>.<span class="py-src-variable">getAllRawHeaders</span>()))
388
<span class="py-src-variable">finished</span> = <span class="py-src-variable">Deferred</span>()
389
<span class="py-src-variable">response</span>.<span class="py-src-variable">deliverBody</span>(<span class="py-src-variable">BeginningPrinter</span>(<span class="py-src-variable">finished</span>))
390
<span class="py-src-keyword">return</span> <span class="py-src-variable">finished</span>
391
<span class="py-src-variable">d</span>.<span class="py-src-variable">addCallback</span>(<span class="py-src-variable">cbRequest</span>)
393
<span class="py-src-keyword">def</span> <span class="py-src-identifier">cbShutdown</span>(<span class="py-src-parameter">ignored</span>):
394
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">stop</span>()
395
<span class="py-src-variable">d</span>.<span class="py-src-variable">addBoth</span>(<span class="py-src-variable">cbShutdown</span>)
397
<span class="py-src-variable">reactor</span>.<span class="py-src-variable">run</span>()
398
</pre><div class="caption">
399
Inspect the response.
400
- <a href="listings/client/response.py"><span class="filename">listings/client/response.py</span></a></div></div>
403
The <code>BeginningPrinter</code> protocol in this example is passed to
404
<code>Response.deliverBody</code> and the response body is then delivered
405
to its <code>dataReceived</code> method as it arrives. When the body has
406
been completely delivered, the protocol's <code>connectionLost</code>
407
method is called. It is important to inspect the <code>Failure</code>
408
passed to <code>connectionLost</code>. If the response body has been
409
completely received, the failure will wrap a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.client.ResponseDone.html" title="twisted.web.client.ResponseDone">twisted.web.client.ResponseDone</a></code> exception. This
410
indicates that it is <em>known</em> that all data has been received. It
411
is also possible for the failure to wrap a <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.web.http.PotentialDataLoss.html" title="twisted.web.http.PotentialDataLoss">twisted.web.http.PotentialDataLoss</a></code> exception: this
412
indicates that the server framed the response such that there is no way
413
to know when the entire response body has been received. Only
414
HTTP/1.0 servers should behave this way. Finally, it is possible for
415
the exception to be of another type, indicating guaranteed data loss for
416
some reason (a lost connection, a memory error, etc).
420
Just as protocols associated with a TCP connection are given a transport,
421
so will be a protocol passed to <code>deliverBody</code>. Since it makes
422
no sense to write more data to the connection at this stage of the
423
request, though, the transport <em>only</em> provides <code class="API"><a href="http://twistedmatrix.com/documents/10.0.0/api/twisted.internet.interfaces.IPushProducer.html" title="twisted.internet.interfaces.IPushProducer">IPushProducer</a></code>. This allows the
424
protocol to control the flow of the response data: a call to the
425
transport's <code>pauseProducing</code> method will pause delivery; a
426
later call to <code>resumeProducing</code> will resume it. If it is
427
decided that the rest of the response body is not desired,
428
<code>stopProducing</code> can be used to stop delivery permanently;
429
after this, the protocol's <code>connectionLost</code> method will be
434
An important thing to keep in mind is that the body will only be read
435
from the connection after <code>Response.deliverBody</code> is called.
436
This also means that the connection will remain open until this is done
437
(and the body read). So, in general, any response with a body
438
<em>must</em> have that body read using <code>deliverBody</code>. If the
439
application is not interested in the body, it should issue a
440
<em>HEAD</em> request or use a protocol which immediately calls
441
<code>stopProducing</code> on its transport.
446
<a name="auto5"/></h2>
449
You should now understand the basics of the Twisted Web HTTP client. In
450
particular, you should understand:
455
How to issue requests with arbitrary methods, headers, and bodies.
458
How to access the response version, code, phrase, headers, and body.
461
How to control the streaming of the response body.
466
<p><a href="index.html">Index</a></p>
467
<span class="version">Version: 10.0.0</span>
b'\\ No newline at end of file'