[英]Post request with multipart/form-data in appengine python not working
I'm attempting to send a multipart post request from an appengine app to an external (django) api hosted on dotcloud.我正在尝试将来自 Appengine 应用程序的多部分发布请求发送到托管在 dotcloud 上的外部 (django) api。 The request includes some text and a file (pdf) and is sent using the following code
该请求包括一些文本和一个文件 (pdf),并使用以下代码发送
from google.appengine.api import urlfetch
from poster.encode import multipart_encode
from libs.poster.streaminghttp import register_openers
register_openers()
file_data = self.request.POST['file_to_upload']
the_file = file_data
send_url = "http://127.0.0.1:8000/"
values = {
'user_id' : '12341234',
'the_file' : the_file
}
data, headers = multipart_encode(values)
headers['User-Agent'] = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
data = str().join(data)
result = urlfetch.fetch(url=send_url, payload=data, method=urlfetch.POST, headers=headers)
logging.info(result.content)
When this method runs Appengine gives the following warning (I'm not sure if it's related to my issue)当此方法运行时 Appengine 给出以下警告(我不确定它是否与我的问题有关)
Stripped prohibited headers from URLFetch request: ['Content-Length']
And Django sends through the following error而Django发送通过以下报错
<class 'django.utils.datastructures.MultiValueDictKeyError'>"Key 'the_file' not found in <MultiValueDict: {}>"
The django code is pretty simple and works when I use the postman chrome extension to send a file. django 代码非常简单,并且在我使用 postman chrome 扩展程序发送文件时有效。
@csrf_exempt
def index(request):
try:
user_id = request.POST["user_id"]
the_file = request.FILES["the_file"]
return HttpResponse("OK")
except:
return HttpResponse(sys.exc_info())
If I add如果我添加
print request.POST.keys()
I get a dictionary containing user_id and the_file indicating that the file is not being sent as a file.我得到一个包含 user_id 和 the_file 的字典,表明该文件没有作为文件发送。 if I do the same for FILES ie
如果我对文件做同样的事情,即
print request.FILES.keys()
I get en empty list [].我得到一个空列表 []。
I've changed my question to implement the suggestion of someone1 however this still fails.我已经更改了我的问题以实施 someone1 的建议,但这仍然失败。 I also included the headers addition recommended by the link Glenn sent, but no joy.
我还包含了 Glenn 发送的链接推荐的标头添加,但并不令人满意。
I've also tried sending the_file as variations of我也试过发送 the_file 作为变体
the_file = file_data.file
the_file = file_data.file.read()
But I get the same error.但我得到了同样的错误。
I've also tried editing my django app to我也试过将我的 django 应用程序编辑为
the_file = request.POST["the_file"]
However when I try to save the file locally with但是,当我尝试在本地保存文件时
path = default_storage.save(file_location, ContentFile(the_file.read()))
it fails with它失败了
<type 'exceptions.AttributeError'>'unicode' object has no attribute 'read'<traceback object at 0x101f10098>
similarly if I try access the_file.file (as I can access in my appengine app) it tells me同样,如果我尝试访问 the_file.file(因为我可以在我的应用引擎应用程序中访问),它会告诉我
<type 'exceptions.AttributeError'>'unicode' object has no attribute 'file'<traceback object at 0x101f06d40>
Here is some code I tested locally that should do the trick (I used a different handler than webapp2 but tried to modify it to webapp2. You'll also need the poster lib found here http://atlee.ca/software/poster/ ):这是我在本地测试的一些代码,应该可以解决问题(我使用了与 webapp2 不同的处理程序,但试图将其修改为 webapp2。您还需要在此处找到的海报库http://atlee.ca/software/poster/ ):
In your POST handler on GAE:在 GAE 上的 POST 处理程序中:
from google.appengine.api import urlfetch
from poster.encode import multipart_encode
payload = {}
payload['test_file'] = self.request.POST['test_file']
payload['user_id'] = self.request.POST['user_id']
to_post = multipart_encode(payload)
send_url = "http://127.0.0.1:8000/"
result = urlfetch.fetch(url=send_url, payload="".join(to_post[0]), method=urlfetch.POST, headers=to_post[1])
logging.info(result.content)
Make sure your HTML form contains method="POST" enctype="multipart/form-data"
.确保您的 HTML 表单包含
method="POST" enctype="multipart/form-data"
。 Hope this helps!希望这可以帮助!
EDIT: I tried using the webapp2 handler and realized the way files are served are different than how the framework I used to test with works (KAY).编辑:我尝试使用 webapp2 处理程序并意识到提供文件的方式与我用来测试的框架的工作方式不同 (KAY)。 Here is updated code that should do the trick (tested on production):
这是应该可以解决问题的更新代码(已在生产中测试):
import webapp2
from google.appengine.api import urlfetch
from poster.encode import multipart_encode, MultipartParam
class UploadTest(webapp2.RequestHandler):
def post(self):
payload = {}
file_data = self.request.POST['test_file']
payload['test_file'] = MultipartParam('test_file', filename=file_data.filename,
filetype=file_data.type,
fileobj=file_data.file)
payload['name'] = self.request.POST['name']
data,headers= multipart_encode(payload)
send_url = "http://127.0.0.1:8000/"
t = urlfetch.fetch(url=send_url, payload="".join(data), method=urlfetch.POST, headers=headers)
self.response.headers['Content-Type'] = 'text/plain'
self.response.out.write(t.content)
def get(self):
self.response.out.write("""
<html>
<head>
<title>File Upload Test</title>
</head>
<body>
<form action="" method="POST" enctype="multipart/form-data">
<input type="text" name="name" />
<input type="file" name="test_file" />
<input type="submit" value="Submit" />
</form>
</body>
</html>""")
You're urlencoding the data where you should be multipart_encoding it.您正在对应该对其进行 multipart_encoding 的数据进行 urlencoding。 Have a look at this: Trying to post multipart form data in python, won't post
看看这个: Trying to post multipart form data in python, won't post
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.