5

appengineアプリからdotcloudでホストされている外部(django)APIにマルチパートPOSTリクエストを送信しようとしています。リクエストにはテキストとファイル(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コードは非常にシンプルで、postmanchrome拡張機能を使用してファイルを送信すると機能します。

@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>

同様に、(appengineアプリでアクセスできるように)the_file.fileにアクセスしようとすると、

<type 'exceptions.AttributeError'>'unicode' object has no attribute 'file'<traceback object at 0x101f06d40>
4

2 に答える 2

9

これが私がローカルでテストしたトリックを実行するコードです(webapp2とは異なるハンドラーを使用しましたが、webapp2に変更しようとしました。http: //atlee.ca/software/poster/にあるposterlibも必要です。)::

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>""")
于 2012-04-13T16:42:54.670 に答える
2

multipart_encodingする必要がある場所でデータをurlencodingしています。これを見てください:Pythonでマルチパートフォームデータを投稿しようとすると、投稿されません

于 2012-04-12T00:03:50.820 に答える