扭曲得到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)
方法来获得的结果?
我错过了将这两个组件连接在一起的位?
答
好的,所以就像拨打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()
我现在可以写我收到的文件内容,并回读结果。
答
如果内容类型是application/x-www-form-urlencoded或multipart/form-data, 正文将被解析并放入request.args字典中。
如果主体太大,则写入临时文件,否则写入StringIO。
正文被读取后,方法finish()被调用。您可以继承Request,并使用此方法削减身体或做其他事情。
答
,如果你想用身体一个简单的POST(不是文件),你可以做如下
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
我们在实际的代码使用上面你可以即
d = httpRequest('htpp://...', post_data_as_dictionary, some_headers, 'POST')
d.addCallback(your_ok_callback_function)
d.addErrback(your_errorback_function)
例头应该像
headers = {'Accept' : ['application/json',],
'Content-Type': ['application/x-www-form-urlencoded',]
}
我希望帮助
为了将来的参考,我建议不要执行由os.stat()。st_size设置的内容长度的request.write(fd.read())。我遇到了一个问题,我在request.write(fd.read())处得到IOError设备上没有剩余空间。 如果你有内存,我建议首先将文件读入缓冲区,然后根据len(buf)做内容长度。然后request.write(buf)。 – 2016-08-17 22:33:52