Отправить запрос с multipart/form-data в Python Appengine не работает
Я пытаюсь отправить многочастный пост-запрос из приложения appengine на внешний (django) API, размещенный на dotcloud. Запрос включает в себя текст и файл (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)
При запуске этого метода Appengine выдает следующее предупреждение (я не уверен, связано ли это с моей проблемой)
Stripped prohibited headers from URLFetch request: ['Content-Length']
И Django отправляет через следующую ошибку
<class 'django.utils.datastructures.MultiValueDictKeyError'>"Key 'the_file' not found in <MultiValueDict: {}>"
Код 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())
Если я добавлю
print request.POST.keys()
Я получаю словарь, содержащий user_id и the_file, указывающий, что файл не отправляется как файл. если я делаю то же самое для файлов, т.е.
print request.FILES.keys()
Я получаю пустой список [].
РЕДАКТИРОВАТЬ 1:
Я изменил свой вопрос, чтобы реализовать предложение кого-то1, однако это все еще не удается. Я также включил добавление заголовков, рекомендованное по ссылке, отправленной Гленном, но не радости.
РЕДАКТИРОВАТЬ 2:
Я также попытался отправить the_file как варианты
the_file = file_data.file
the_file = file_data.file.read()
Но я получаю ту же ошибку.
РЕДАКТИРОВАТЬ 3:
Я также попытался отредактировать мое приложение Django в
the_file = request.POST["the_file"]
Однако, когда я пытаюсь сохранить файл локально с
path = default_storage.save(file_location, ContentFile(the_file.read()))
это терпит неудачу с
<type 'exceptions.AttributeError'>'unicode' object has no attribute 'read'<traceback object at 0x101f10098>
Точно так же, если я пытаюсь получить доступ к the_file.file (как я могу получить доступ в моем приложении appengine), он говорит мне,
<type 'exceptions.AttributeError'>'unicode' object has no attribute 'file'<traceback object at 0x101f06d40>
2 ответа
Вот некоторый код, который я протестировал локально и который должен был помочь (я использовал другой обработчик, нежели webapp2, но попытался изменить его на webapp2. Вам также понадобится библиотека исходных текстов, найденная здесь http://atlee.ca/software/poster/):
В вашем обработчике POST на GAE:
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)
Убедитесь, что ваша HTML-форма содержит method="POST" enctype="multipart/form-data"
, Надеюсь это поможет!
РЕДАКТИРОВАТЬ: я пытался использовать обработчик webapp2 и понял, что способ подачи файлов отличается от того, как работает каркас, который я использовал для тестирования с (KAY). Вот обновленный код, который должен помочь (проверено на производстве):
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>""")
Вы urlencoding данных, где вы должны быть multipart_encoding его. Посмотрите на это: Попытка опубликовать данные из нескольких частей формы в Python, не будет публиковать