Google AppEngine (Python) からファイルアップロード

Google AppEngineで外部サイトにHTTPリクエストを発行する際に使う urlfetch は、post関数を持っていません。通常のテキストデータの送信であれば、POSTメソッドの発行自体は method=urlfetch.POST を fetch() の引数に渡すことで可能です。しかし、ファイルアップロードを行いたいなどの用途でmultipart requestを行いたい場合、適切にリクエストをエンコードしてあげる必要があります。


このエンコードのために簡単に利用できる小さなPython Packageとして、poster.encode が利用できます。


AppEngineで使うためには https://pypi.python.org/pypi/poster/ から poster-0.8.1.tar.gz をダウンロードして展開し、中の poster-0.8.1/poster を、アプリケーションのトップ階層にコピーしておく必要があります。


下記は、受信したPOSTリクエストをそのままurl変数で指定されたサイトに再POSTする例です。file というnameのparamにファイルを指定することができます。以下の例では名前決めうちになっていますが、v.filename などが参照できるかをチェックして分岐しても良いでしょう。


なお、あまりに大きいファイル(10MBを超えるなど)はエラーになってしまうようです。

from google.appengine.api import urlfetch
from poster.encode import multipart_encode, MultipartParam
import urllib
import webapp2

class FileUploadTest(webapp2.RequestHandler):
    def post(self):
        url = 'https://example.com/file_upload'
        params = []
        for param in self.request.POST:
            v = self.request.POST[param]
            if param == 'file':
                params.append(MultipartParam(param, filename=v.filename, filetype=v.type, filesize=v.length, fileobj=v.file))
            else:
                params.append(MultipartParam(param, value=v))
        data, headers = multipart_encode(params)
        return urlfetch.fetch(url, payload="".join(data), headers=headers, method=urlfetch.POST)