2012-07-18 5 views
8

Ok、POSTリクエストの本体がねじれている

これは、人がいつもやっているので簡単です。私は、POST要求の本体にツイストされたAgentを送りたいと思っています。これは、ねじれたFileBodyProducerで作成されます。サーバー側ではrender_POSTメソッドのrequestオブジェクトを取得します。

ボディを取得するにはどうすればよいですか?

サーバー:

from twisted.web import server, resource 
from twisted.internet import reactor 


class Simple(resource.Resource): 
    isLeaf = True 
    def render_GET(self, request): 
     return "{0}".format(request.args.keys()) 
    def render_POST(self, request): 
     return "{0}".format(request.data) 
     with open(request.args['filename'][0], 'rb') as fd: 
      fd.write(request.write()) 

site = server.Site(Simple()) 
reactor.listenTCP(8080, site) 
reactor.run() 

クライアント:

from StringIO import StringIO 

from twisted.internet import reactor 
from twisted.web.client import Agent 
from twisted.web.http_headers import Headers 

from twisted.web.client import FileBodyProducer 
from twisted.internet.defer import Deferred 
from twisted.internet.protocol import Protocol 
from pprint import pformat 

class BeginningPrinter(Protocol): 
    def __init__(self, finished): 
     self.finished = finished 
     self.remaining = 1024 * 10 

    def dataReceived(self, bytes): 
     if self.remaining: 
      display = bytes[:self.remaining] 
      print 'Some data received:' 
      print display 
      self.remaining -= len(display) 

    def connectionLost(self, reason): 
     print 'Finished receiving body:', reason.getErrorMessage() 
     self.finished.callback(None) 

agent = Agent(reactor) 
body = FileBodyProducer(StringIO("hello, world")) 
d = agent.request(
    'POST', 
    'http://127.0.0.1:8080/', 
    Headers({'User-Agent': ['Twisted Web Client Example'], 
      'Content-Type': ['text/x-greeting']}), 
    body) 

def cbRequest(response): 
    print 'Response version:', response.version 
    print 'Response code:', response.code 
    print 'Response phrase:', response.phrase 
    print 'Response headers:' 
    print pformat(list(response.headers.getAllRawHeaders())) 
    finished = Deferred() 
    response.deliverBody(BeginningPrinter(finished)) 
    return finished 
d.addCallback(cbRequest) 

def cbShutdown(ignored): 
    reactor.stop() 
d.addBoth(cbShutdown) 

reactor.run() 

私は消費者側leave something to be desiredを設定するために見つけることができる唯一のドキュメント。主に消費者がwrite(data)メソッドを使用してにどのようにしての結果を受け取ることができますか?

これらの2つのコンポーネントを一緒に接続するのに欠けている部分は何ですか?

答えて

13

大丈夫ですので、request.content.read()と同じくらい簡単です。これは、私が知る限り、APIに文書化されていません。

from twisted.internet import reactor 
from twisted.web.client import Agent 
from twisted.web.http_headers import Headers 

from twisted.web.client import FileBodyProducer 
from twisted.internet.defer import Deferred 
from twisted.internet.protocol import Protocol 
from pprint import pformat 

class BeginningPrinter(Protocol): 
    def __init__(self, finished): 
     self.finished = finished 
     self.remaining = 1024 * 10 

    def dataReceived(self, bytes): 
     if self.remaining: 
      display = bytes[:self.remaining] 
      print 'Some data received:' 
      print display 
      self.remaining -= len(display) 

    def connectionLost(self, reason): 
     print 'Finished receiving body:', reason.getErrorMessage() 
     self.finished.callback(None) 

class SaveContents(Protocol): 
    def __init__(self, finished, filesize, filename): 
     self.finished = finished 
     self.remaining = filesize 
     self.outfile = open(filename, 'wb') 

    def dataReceived(self, bytes): 
     if self.remaining: 
      display = bytes[:self.remaining] 
      self.outfile.write(display) 
      self.remaining -= len(display) 
     else: 
      self.outfile.close() 

    def connectionLost(self, reason): 
     print 'Finished receiving body:', reason.getErrorMessage() 
     self.outfile.close() 
     self.finished.callback(None) 

agent = Agent(reactor) 
f = open('70935-new_barcode.pdf', 'rb') 
body = FileBodyProducer(f) 
d = agent.request(
    'POST', 
    'http://127.0.0.1:8080?filename=test.pdf', 
    Headers({'User-Agent': ['Twisted Web Client Example'], 
      'Content-Type': ['multipart/form-data; boundary=1024'.format()]}), 
    body) 

def cbRequest(response): 
    print 'Response version:', response.version 
    print 'Response code:', response.code 
    print 'Response phrase:', response.phrase 
    print 'Response headers:' 
    print 'Response length:', response.length 
    print pformat(list(response.headers.getAllRawHeaders())) 
    finished = Deferred() 
    response.deliverBody(SaveContents(finished, response.length, 'test2.pdf')) 
    return finished 
d.addCallback(cbRequest) 

def cbShutdown(ignored): 
    reactor.stop() 
d.addBoth(cbShutdown) 

reactor.run() 

そして、ここでは、サーバーがあります:

from twisted.web import server, resource 
from twisted.internet import reactor 
import os 

# multi part encoding example: http://marianoiglesias.com.ar/python/file-uploading-with-multi-part-encoding-using-twisted/ 
class Simple(resource.Resource): 
    isLeaf = True 
    def render_GET(self, request): 
     return "{0}".format(request.args.keys()) 
    def render_POST(self, request): 
     with open(request.args['filename'][0], 'wb') as fd: 
      fd.write(request.content.read()) 
     request.setHeader('Content-Length', os.stat(request.args['filename'][0]).st_size) 
     with open(request.args['filename'][0], 'rb') as fd: 
      request.write(fd.read()) 
     request.finish() 
     return server.NOT_DONE_YET 

site = server.Site(Simple()) 
reactor.listenTCP(8080, site) 
reactor.run() 

私は今、私が受け取ったファイルの内容を書き込み、その結果を読み戻すことができます

はここで、クライアントのために更新されたコードです。

+0

今後の参考として、os.stat()。st_sizeで設定されたcontent-lengthでrequest.write(fd.read())を実行しないことをお勧めします。私はrequest.write(fd.read())でデバイス上にIOErrorが残っていないという問題がありました。 メモリがあれば、まずファイルをバッファに読み込み、次にlen(buf)に基づいてコンテンツ長を実行することをお勧めします。 request.write(buf)を実行します。 –

2

コンテンツタイプがapplication/x-www-form-urlencodedまたはmultipart/form-dataの場合、 本文は解析され、request.args dictに入れられます。

ボディが大きすぎる場合は、一時ファイルに書き込まれます。そうでない場合は、StringIOに書き込まれます。

ボディが読み込まれた後、finish()メソッドが呼び出されます。 Requestをサブクラス化し、 はこのメソッドでボディをパースするか、sth elseを実行します。

0

あなたが身体を持つ単純なPOST(ないファイル)を作成したい場合は

d = httpRequest('htpp://...', post_data_as_dictionary, some_headers, 'POST') 
d.addCallback(your_ok_callback_function) 
d.addErrback(your_errorback_function) 

例ヘッダ、すなわちことができ、実際のコードで上記使用することを今

import urllib 
from twisted.internet import protocol 
from twisted.internet import defer 
from twisted.web.http_headers import Headers 
from twisted.internet import reactor 
from twisted.web.client import Agent 
from twisted.web.iweb import IBodyProducer 
from zope.interface import implements 
from twisted.internet.defer import succeed 

class StringProducer(object): 
    implements(IBodyProducer) 

    def __init__(self, body): 
     self.body = body 
     self.length = len(body) 

    def startProducing(self, consumer): 
     consumer.write(self.body) 
     return succeed(None) 

    def pauseProducing(self): 
     pass 

    def stopProducing(self): 
     pass 

class SimpleReceiver(protocol.Protocol): 
    def __init__(self, d): 
     self.buf = ''; self.d = d 

    def dataReceived(self, data): 
     self.buf += data 

    def connectionLost(self, reason): 
     self.d.callback(self.buf) 

def httpRequest(url, values=None, headers=None, method='POST'): 

    agent = Agent(reactor) 
    data = urllib.urlencode(values) if values else None 

    d = agent.request(method, url, Headers(headers) if headers else {}, 
     StringProducer(data) if data else None 
     ) 

    def handle_response(response): 
     if response.code == 204: 
      d = defer.succeed('') 
     else: 
      d = defer.Deferred() 
      response.deliverBody(SimpleReceiver(d)) 
     return d 

    d.addCallback(handle_response) 
    return d 

を次のようにあなたが行うことができます

headers = {'Accept' : ['application/json',], 
      'Content-Type': ['application/x-www-form-urlencoded',] 
} 

のようになります。私はそれが

を役に立てば幸い
関連する問題