Google Apps Scriptでファイルを送れない
HTTPの通信を用いて、ファイルを送るとき、curlやpythonでは、コマンドでfile指定すれば、簡単にmultipartのファイルを送れる。しかし、Google Apps Script上では、簡単にmultipartを送信することができない。
ファイルを送信するときは、multipart/form-dataを利用しているらしい
今、Microsoft Face APIを利用して、画像のバイナリデータを送信したいのだが、fileメソッドがないので、自作する必要がある。PythonからFace APIで画像のバイナリファイルを送信することはできるようで、その時はrequests.post(file = hoge)で成功していた。なのえd、ということで、Pythonのrequestsモジュールのfileではどのような処理をしているのか調べたところ、multipartという言葉に出会った
ちなみにファイルを送信するときに一般的に利用されるのは、multipart/form-dataもあるが、base64方式で送信することもあるそう。ただし、ほとんどの場合は前者を利用するとが多いみたいだ。
multipart/form-dataとは
HTTP Multipartリクエストは、HTTPサーバーにファイルやそれ以外のファイルを送信す
るときに利用される。multipart/form-dataメッセージは、boundariesによって区切られたいくつかの部分がある。それぞれの部分は、Content-Diposisionヘッダーがspン材していて、その値はform-dataとなっている。もし、そのファイルがサーバーに送られるときは、ContentTypeも一緒に含まれている必要がある。
The HTTP multipart request is commonly used to upload files and other data over to a HTTP Server. A “multipart/form-data” message contains a series of parts separated by boundaries. Each part should contain the “Content-Disposition” header whose value is “form-data” and if a file is being sent to the server, the contentType should also be included.(Upload Files using the Multipart post method with Google Apps Scriptから翻訳)
らしい。これだけ読んでもよくわからない。
multipart/form-dataについて調べてみる
multipart/form-dataについての通信規約については、Returning Values from Forms: multipart/form-data(RFC)を参照すると正式な内容がわかるはず。日本語で翻訳されていてわかりやすいのは、この記事っぽい。
multipart/form-data (MIME)
らしい。
MIME型 multipart/form-data は、 HTML のフォームの提出で使われるデータ形式です。
application/x-www-form-urlencoded と並んで HTTP POST 要求で最もよく用いられる MIME型の1つです。 パーセント符号化を使う application/x-www-form-url-encoded では扱いづらいファイル (<input type=file>) の提出のために開発されましたが、 ファイルを扱わない場合にも使われています。
Google Apps Script経由で、送信するときのサンプルスクリプトは
https://ctrlq.org/code/20096-upload-files-multipart-post
がよいみたいだ。
// Written by Amit Agarwal www.labnol.org function uploadFile() { var boundary = "labnol"; var blob = DriveApp.getFileById(GOOGLE_DRIVE_FILE_ID).getBlob(); var attributes = "{\"name\":\"abc.pdf\", \"parent\":{\"id\":\"FOLDER_ID\"}}"; var requestBody = Utilities.newBlob( "--"+boundary+"\r\n" + "Content-Disposition: form-data; name=\"attributes\"\r\n\r\n" + attributes+"\r\n"+"--"+boundary+"\r\n" + "Content-Disposition: form-data; name=\"file\"; filename=\""+blob.getName()+"\"\r\n" + "Content-Type: " + blob.getContentType()+"\r\n\r\n").getBytes() .concat(blob.getBytes()) .concat(Utilities.newBlob("\r\n--"+boundary+"--\r\n").getBytes()); var options = { method: "post", contentType: "multipart/form-data; boundary="+boundary, payload: requestBody, muteHttpExceptions: true, headers: {'Authorization': 'Bearer ' + getBoxService_().getAccessToken()} }; var request = UrlFetchApp.fetch("https://upload.box.com/api/2.0/files/content", options); Logger.log(request.getContentText()); }