【问题标题】:Post request with multipart/form-data in appengine python not working在 appengine python 中使用 multipart/form-data 发布请求不起作用
【发布时间】:2012-04-21 10:22:42
【问题描述】:

我正在尝试将多部分发布请求从 appengine 应用程序发送到托管在 dotcloud 上的外部 (django) api。该请求包括一些文本和一个文件 (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 代码非常简单,当我使用邮递员 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:

我已更改我的问题以实施某人的建议,但这仍然失败。我还包括了 Glenn 发送的链接推荐的标题添加,但没有任何乐趣。

编辑 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>

【问题讨论】:

    标签: python django google-app-engine post


    【解决方案1】:

    您正在对应该多部分编码的数据进行 urlencoding。看看这个:Trying to post multipart form data in python, won't post

    【讨论】:

      【解决方案2】:

      这是我在本地测试的一些代码,应该可以解决问题(我使用了与 webapp2 不同的处理程序,但尝试将其修改为 webapp2。您还需要在 http://atlee.ca/software/poster/ 找到的海报库):

      在 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)
      

      确保您的 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>""")
      

      【讨论】:

      • 您好,感谢您的代码。此处提交的 appengine 中有一个错误 (code.google.com/p/googleappengine/issues/detail?id=627),它限制了 multipart_encode 方法的有用性。我现在只是在测试一种解决方法。
      • 我不完全确定这个错误会影响你想要完成的事情。实际上,我不知道该错误是否仍然有效,因为您可以对数据进行编码并将其打包为 POST urlfetch 中的有效负载,就像我使用海报库给出的示例代码一样。
      • 完美!编辑后的版本完全符合要求 - 非常感谢您的帮助,这让我分心!
      猜你喜欢
      • 1970-01-01
      • 2022-01-13
      • 1970-01-01
      • 2013-08-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多