LoginSignup
0
0

More than 1 year has passed since last update.

GASのOAuth1ライブラリでform-dataフォーマットが使えない理由

Posted at

背景

GASで画像を投稿する際、私が確認できたサイトで、OAuth1ライブラリを使用している物は全て画像をbase64エンコードしてアップロードしています。

それはOAuth1ライブラリを用いてmultipart/form-dataで投稿しようとすると認証エラーが発生するからです。

しかしmultipart/form-dataで投稿したほうが通信量も少なければbase64エンコードする時間も節約できるので出来ればmultipart/form-dataで投稿がしたい。

そこで、なぜOAuth1ライブラリを使用すると、multipart/form-dataで投稿が出来ないのか調査しました。

原因

GASのUrlFetchApp.fetchはcontentTypeの指定が無いかつpayloadにBlobインスタンスが含まれていると自動でmultipart/form-dataフォーマットしてくれる優れものです。

が、原因はこの「contentTypeの指定が無い」の部分にあります。

OAuth1ライブラリのfetch部分の実装を見ると以下のようなコードがあります。(419行目446行目)

if (params.payload && (!params.contentType ||
      params.contentType == 'application/x-www-form-urlencoded')) {
   //続く

これすなわちcontentTypeの指定が無い場合とcontentTypeがapplication/x-www-form-urlencodedの場合の処理が同じということです。

payloadにBlobインスタンスがある場合もcontentTypeの指定が無ければapplication/x-www-form-urlencodedと同様に処理がされて、payloadはapplication/x-www-form-urlencodedにフォーマットがされます。

つまり、ユーザーがmultipart/form-dataでPOSTしようと思ってcontentTypeを空にしても、実際はapplication/x-www-form-urlencodedでPOSTがされて、エラーが発生するという訳です。

対処法

OAuth1ライブラリを少し改良します。
distファイルのOAuth1.gsが統合ファイル(多分)なのでそれをGASにコピペしてください。

方法1.contentTypeが空の場合はそのままスルーさせる

貼り付けたファイルの536,563行目を以下のようにします。

-if (params.payload && (!params.contentType ||
- params.contentType == 'application/x-www-form-urlencoded'))
+if (params.payload && params.contentType == 'application/x-www-form-urlencoded')

以下のようにしてPOSTします。

service.fetch("https://upload.twitter.com/1.1/media/upload.json",{
  method:"post",
  payload:{
    media:<Blob>
  }
})

しかし、application/x-www-form-urlencodedの場合もcontentTypeの指定が必須になるので、そこは注意してください。

方法2.contentTypeがmultipart/form-data指定の時はcontentTypeを空にする

ライブラリにはスルーさせて、UrlFetchAppにフォーマットを任せたいので、UrlFetchApp.fetchの直前にcontentTypeが特定のワードだった時にcontentTypeを削除するようにします。

    params.escaping = false;
  }
+ if(params.contentType==="multipart/form-data")
+   delete params.contentType
  return UrlFetchApp.fetch(url, params);

以下のようにしてPOSTします

service.fetch("https://upload.twitter.com/1.1/media/upload.json",{
  method:"post",
  payload:{
    media:<Blob>
  },
  contentType:"multipart/form-data"
})

こっちの場合はapplication/x-www-form-urlencodedの場合は従来通りにcontentTypeを省略できます。

最後に

Google様のライブラリが原因なんて思ってもいませんでした。
案外疑ってみるものですね。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0